mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
Merge pull request #33738 from BerriAI/litellm_lit_4116_drop_params_string_coerce
fix(utils): honor string drop_params values from config and DB deployments
This commit is contained in:
commit
13005cb831
18 changed files with 511 additions and 67 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 drop_params_env_flag
|
||||
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 = drop_params_env_flag(os.environ, verbose_logger)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
# What is this?
|
||||
## Helper utilities
|
||||
import copy
|
||||
import logging
|
||||
from collections.abc import Iterable, Mapping
|
||||
from typing import TYPE_CHECKING, Any, Final, Literal
|
||||
|
||||
import httpx
|
||||
from pydantic import TypeAdapter, ValidationError
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.types.llms.openai import AllMessageValues, OpenAIChatCompletionFinishReason
|
||||
|
|
@ -37,6 +39,41 @@ def safe_divide_seconds(seconds: float, denominator: float, default: float | Non
|
|||
return float(seconds / denominator)
|
||||
|
||||
|
||||
_DROP_PARAMS_BOOL: Final = TypeAdapter(bool)
|
||||
|
||||
|
||||
def normalize_drop_params(value: object) -> bool | None:
|
||||
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)
|
||||
except ValidationError:
|
||||
return None
|
||||
|
||||
|
||||
def drop_params_flag(value: object, source: str, logger: logging.Logger) -> bool:
|
||||
normalized: Final = normalize_drop_params(value)
|
||||
if normalized is None and value is not None:
|
||||
logger.warning("%s=%r is not a flag value, treating it as off", source, value)
|
||||
return bool(normalized)
|
||||
|
||||
|
||||
DROP_PARAMS_ENV_VAR: Final = "LITELLM_DROP_PARAMS"
|
||||
|
||||
|
||||
def drop_params_env_flag(environ: Mapping[str, str], logger: logging.Logger) -> bool:
|
||||
configured: Final = environ.get(DROP_PARAMS_ENV_VAR, "").strip()
|
||||
if configured == "":
|
||||
return False
|
||||
normalized: Final = normalize_drop_params(configured)
|
||||
if normalized is None:
|
||||
logger.warning(
|
||||
"%s=%r is not a flag value, treating it as on. Set it to true or false", DROP_PARAMS_ENV_VAR, configured
|
||||
)
|
||||
return True
|
||||
return normalized
|
||||
|
||||
|
||||
def safe_divide(
|
||||
numerator: float,
|
||||
denominator: float,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ from litellm.litellm_core_utils.asyncify import asyncify
|
|||
from litellm.litellm_core_utils.audio_utils.utils import resolve_speech_media_type
|
||||
from litellm.litellm_core_utils.core_helpers import (
|
||||
_get_parent_otel_span_from_kwargs,
|
||||
drop_params_flag,
|
||||
get_litellm_metadata_from_kwargs,
|
||||
)
|
||||
from litellm.litellm_core_utils.credential_accessor import CredentialAccessor
|
||||
|
|
@ -5519,6 +5520,8 @@ class ProxyConfig:
|
|||
|
||||
parse_budget_reset_time(value)
|
||||
setattr(litellm, key, value)
|
||||
elif key == "drop_params":
|
||||
litellm.drop_params = drop_params_flag(value, "litellm_settings.drop_params", verbose_proxy_logger)
|
||||
else:
|
||||
verbose_proxy_logger.debug(
|
||||
"%s setting litellm.%s=%s%s",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from litellm.completion_extras.litellm_responses_transformation.transformation i
|
|||
from litellm.constants import request_timeout
|
||||
from litellm.integrations.anthropic_cache_control_hook import CARRY_UNMATCHED_MESSAGE_POINTS
|
||||
from litellm.litellm_core_utils.asyncify import run_async_function
|
||||
from litellm.litellm_core_utils.core_helpers import normalize_drop_params
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
from litellm.litellm_core_utils.prompt_templates.common_utils import (
|
||||
update_responses_input_with_model_file_ids,
|
||||
|
|
@ -1257,7 +1258,7 @@ def responses(
|
|||
responses_api_provider_config=responses_api_provider_config,
|
||||
response_api_optional_params=response_api_optional_params,
|
||||
allowed_openai_params=allowed_openai_params,
|
||||
drop_params=request_drop_params if isinstance(request_drop_params, bool) else None,
|
||||
drop_params=normalize_drop_params(request_drop_params),
|
||||
)
|
||||
|
||||
litellm_logging_obj.update_from_kwargs(
|
||||
|
|
@ -2085,7 +2086,7 @@ def compact_responses(
|
|||
responses_api_provider_config=responses_api_provider_config,
|
||||
response_api_optional_params=response_api_optional_params,
|
||||
allowed_openai_params=None,
|
||||
drop_params=request_drop_params if isinstance(request_drop_params, bool) else None,
|
||||
drop_params=normalize_drop_params(request_drop_params),
|
||||
)
|
||||
|
||||
# Pre Call logging
|
||||
|
|
|
|||
|
|
@ -9420,6 +9420,12 @@ class Router:
|
|||
#### VALIDATE MODEL ########
|
||||
# Check if this is a prompt management model before validating as LLM provider
|
||||
litellm_model: Final = deployment.litellm_params.model
|
||||
if isinstance(deployment.litellm_params.drop_params, str):
|
||||
verbose_router_logger.warning(
|
||||
"model=%s drop_params=%r is not a flag value, treating it as unset",
|
||||
deployment.model_name,
|
||||
deployment.litellm_params.drop_params,
|
||||
)
|
||||
is_prompt_management_model = False
|
||||
|
||||
if "/" in litellm_model:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ 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
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from litellm.router import Router
|
||||
|
|
@ -314,6 +316,7 @@ class GenericLiteLLMParams(CredentialLiteLLMParams, CustomPricingLiteLLMParams):
|
|||
timeout: float | str | httpx.Timeout | None = None # if str, pass in as os.environ/
|
||||
stream_timeout: float | str | None = None # timeout when making stream=True calls, if str, pass in as os.environ/
|
||||
max_retries: int | None = None
|
||||
drop_params: bool | str | None = None
|
||||
organization: str | None = None # for openai orgs
|
||||
configurable_clientside_auth_params: CONFIGURABLE_CLIENTSIDE_AUTH_PARAMS = None
|
||||
litellm_credential_name: str | None = None
|
||||
|
|
@ -404,6 +407,18 @@ class GenericLiteLLMParams(CredentialLiteLLMParams, CustomPricingLiteLLMParams):
|
|||
return filtered
|
||||
return data
|
||||
|
||||
@field_validator("drop_params", mode="before")
|
||||
@classmethod
|
||||
def coerce_drop_params(cls, value: object) -> bool | str | None:
|
||||
normalized: Final = normalize_drop_params(value)
|
||||
if normalized is not None:
|
||||
return normalized
|
||||
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
|
||||
return hasattr(self, key)
|
||||
|
|
|
|||
122
litellm/utils.py
122
litellm/utils.py
|
|
@ -80,6 +80,7 @@ from litellm.constants import (
|
|||
PROVIDERS_THAT_AUTHENTICATE_ON_PROVIDER_INFO,
|
||||
TOOL_CHOICE_OBJECT_TOKEN_COUNT,
|
||||
)
|
||||
from litellm.litellm_core_utils.core_helpers import normalize_drop_params
|
||||
from litellm.litellm_core_utils.fallback_generalizations import (
|
||||
match_capability_generalizations,
|
||||
)
|
||||
|
|
@ -3239,7 +3240,7 @@ def get_optional_params_transcription(
|
|||
|
||||
passed_params.pop("OPENAI_TRANSCRIPTION_PARAMS")
|
||||
custom_llm_provider = passed_params.pop("custom_llm_provider")
|
||||
drop_params = passed_params.pop("drop_params")
|
||||
drop_params = normalize_drop_params(passed_params.pop("drop_params"))
|
||||
special_params: Final[Mapping[str, object]] = passed_params.pop("kwargs")
|
||||
for k, v in special_params.items():
|
||||
passed_params[k] = v
|
||||
|
|
@ -3347,7 +3348,7 @@ def get_optional_params_image_gen(
|
|||
model = passed_params.pop("model", None)
|
||||
custom_llm_provider = passed_params.pop("custom_llm_provider")
|
||||
provider_config = passed_params.pop("provider_config", None)
|
||||
drop_params = passed_params.pop("drop_params", None)
|
||||
drop_params = normalize_drop_params(passed_params.pop("drop_params", None))
|
||||
additional_drop_params = passed_params.pop("additional_drop_params", None)
|
||||
special_params: Final[Mapping[str, object]] = passed_params.pop("kwargs")
|
||||
for k, v in special_params.items():
|
||||
|
|
@ -3475,7 +3476,7 @@ def get_optional_params_embeddings(
|
|||
custom_llm_provider = passed_params.pop("custom_llm_provider", None)
|
||||
special_params: Final = passed_params.pop("kwargs")
|
||||
|
||||
drop_params = passed_params.pop("drop_params", None)
|
||||
drop_params = normalize_drop_params(passed_params.pop("drop_params", None))
|
||||
additional_drop_params = passed_params.pop("additional_drop_params", None)
|
||||
allowed_openai_params = passed_params.pop("allowed_openai_params", None) or []
|
||||
# Remove function objects from passed_params to avoid JSON serialization errors
|
||||
|
|
@ -4202,6 +4203,7 @@ def get_optional_params(
|
|||
base_model: str | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
drop_params = normalize_drop_params(drop_params) # rebind-ok: config and DB deployments pass "true" as a string
|
||||
passed_params: Final = locals().copy()
|
||||
special_params: Final = passed_params.pop("kwargs")
|
||||
# Remove base_model from passed_params so it doesn't interfere with
|
||||
|
|
@ -4279,20 +4281,20 @@ def get_optional_params(
|
|||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "anthropic_text":
|
||||
optional_params = litellm.AnthropicTextConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
optional_params = litellm.AnthropicTextConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "cohere_chat" or custom_llm_provider == "cohere":
|
||||
|
|
@ -4301,14 +4303,14 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "triton":
|
||||
optional_params = litellm.TritonConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=drop_params if drop_params is not None else False,
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "maritalk":
|
||||
|
|
@ -4316,35 +4318,35 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "replicate":
|
||||
optional_params = litellm.ReplicateConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "predibase":
|
||||
optional_params = litellm.PredibaseConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "huggingface":
|
||||
optional_params = litellm.HuggingFaceChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "together_ai":
|
||||
optional_params = litellm.TogetherAIChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "vertex_ai" and (
|
||||
model in litellm.vertex_chat_models
|
||||
|
|
@ -4358,7 +4360,7 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "gemini":
|
||||
|
|
@ -4366,21 +4368,21 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "vertex_ai_beta" or (custom_llm_provider == "vertex_ai" and "gemini" in model):
|
||||
optional_params = litellm.VertexGeminiConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif litellm.VertexAIAnthropicConfig.is_supported_model(model=model, custom_llm_provider=custom_llm_provider):
|
||||
optional_params = litellm.VertexAIAnthropicConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "vertex_ai":
|
||||
if model in litellm.vertex_mistral_models:
|
||||
|
|
@ -4389,35 +4391,35 @@ def get_optional_params(
|
|||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
else:
|
||||
optional_params = litellm.MistralConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif model in litellm.vertex_ai_ai21_models:
|
||||
optional_params = litellm.VertexAIAi21Config().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif provider_config is not None:
|
||||
optional_params = provider_config.map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
else: # use generic openai-like param mapping
|
||||
optional_params = litellm.VertexAILlama3Config().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "sagemaker":
|
||||
|
|
@ -4426,7 +4428,7 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "bedrock":
|
||||
BedrockModelInfo: Final = getattr(sys.modules[__name__], "BedrockModelInfo")
|
||||
|
|
@ -4437,14 +4439,14 @@ def get_optional_params(
|
|||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif bedrock_route == "openai":
|
||||
optional_params = litellm.AmazonBedrockOpenAIConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif "anthropic" in bedrock_base_model and bedrock_route == "invoke":
|
||||
if bedrock_base_model in litellm.AmazonAnthropicConfig.get_legacy_anthropic_model_names():
|
||||
|
|
@ -4452,21 +4454,21 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
else:
|
||||
optional_params = litellm.AmazonAnthropicClaudeConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif provider_config is not None:
|
||||
optional_params = provider_config.map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
if bedrock_route == "claude_platform":
|
||||
optional_params = BedrockModelInfo.map_claude_platform_auth_params(
|
||||
|
|
@ -4477,28 +4479,28 @@ def get_optional_params(
|
|||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "ollama":
|
||||
optional_params = litellm.OllamaConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "ollama_chat":
|
||||
optional_params = litellm.OllamaChatConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "nlp_cloud":
|
||||
optional_params = litellm.NLPCloudConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "petals":
|
||||
|
|
@ -4506,35 +4508,35 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "deepinfra":
|
||||
optional_params = litellm.DeepInfraConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "perplexity" and provider_config is not None:
|
||||
optional_params = provider_config.map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "mistral" or custom_llm_provider == "codestral":
|
||||
optional_params = litellm.MistralConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "text-completion-codestral":
|
||||
optional_params = litellm.CodestralTextCompletionConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "text-completion-inception":
|
||||
|
|
@ -4542,7 +4544,7 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
|
||||
elif custom_llm_provider == "databricks":
|
||||
|
|
@ -4550,21 +4552,21 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "nvidia_nim":
|
||||
optional_params = litellm.NvidiaNimConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "cerebras":
|
||||
optional_params = litellm.CerebrasConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "xai":
|
||||
optional_params = litellm.XAIChatConfig().map_openai_params(
|
||||
|
|
@ -4577,77 +4579,77 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "fireworks_ai":
|
||||
optional_params = litellm.FireworksAIConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "volcengine":
|
||||
optional_params = litellm.VolcEngineConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "hosted_vllm":
|
||||
optional_params = litellm.HostedVLLMChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "vllm":
|
||||
optional_params = litellm.VLLMConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "groq":
|
||||
optional_params = litellm.GroqChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "bedrock_mantle":
|
||||
optional_params = litellm.BedrockMantleChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "deepseek":
|
||||
optional_params = litellm.DeepSeekChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "tencent":
|
||||
optional_params = litellm.TencentChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "openrouter":
|
||||
optional_params = litellm.OpenrouterConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "watsonx":
|
||||
optional_params = litellm.IBMWatsonXChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
# WatsonX-text param check
|
||||
for param in passed_params:
|
||||
|
|
@ -4660,21 +4662,21 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "openai":
|
||||
optional_params = litellm.OpenAIConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "nebius":
|
||||
optional_params = litellm.NebiusConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif custom_llm_provider == "azure":
|
||||
_azure_detection_model: Final = base_model or model
|
||||
|
|
@ -4683,14 +4685,14 @@ def get_optional_params(
|
|||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=_azure_detection_model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif litellm.AzureOpenAIGPT5Config.is_model_gpt_5_model(model=_azure_detection_model):
|
||||
optional_params = litellm.AzureOpenAIGPT5Config().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=_azure_detection_model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
else:
|
||||
verbose_logger.debug(
|
||||
|
|
@ -4709,21 +4711,21 @@ def get_optional_params(
|
|||
optional_params=optional_params,
|
||||
model=_azure_detection_model,
|
||||
api_version=api_version,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
elif provider_config is not None:
|
||||
optional_params = provider_config.map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
else: # assume passing in params for openai-like api
|
||||
optional_params = litellm.OpenAILikeChatConfig().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model=model,
|
||||
drop_params=(drop_params if drop_params is not None and isinstance(drop_params, bool) else False),
|
||||
drop_params=bool(drop_params),
|
||||
)
|
||||
# if user passed in non-default kwargs for specific providers/models, pass them along
|
||||
optional_params = add_provider_specific_params_to_optional_params(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
"""Tests for litellm_core_utils.core_helpers module."""
|
||||
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.litellm_core_utils.core_helpers import (
|
||||
_FINISH_REASON_MAP,
|
||||
drop_params_env_flag,
|
||||
drop_params_flag,
|
||||
get_or_create_metadata_bucket,
|
||||
map_finish_reason,
|
||||
normalize_drop_params,
|
||||
reconstruct_model_name,
|
||||
redact_nested_match_and_regex_keys,
|
||||
)
|
||||
|
|
@ -257,6 +262,73 @@ class TestRedactNestedMatchAndRegexKeys:
|
|||
assert redact_nested_match_and_regex_keys("plain") == "plain"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected",
|
||||
[
|
||||
(True, True),
|
||||
(False, False),
|
||||
("true", True),
|
||||
("True", True),
|
||||
(" TRUE ", True),
|
||||
("false", False),
|
||||
("False", False),
|
||||
("yes", True),
|
||||
("off", False),
|
||||
("1", True),
|
||||
(1, True),
|
||||
(0, False),
|
||||
(None, None),
|
||||
("", None),
|
||||
("os.environ/DROP_PARAMS", None),
|
||||
("v2:gcm:not-a-flag", None),
|
||||
(2, None),
|
||||
],
|
||||
)
|
||||
def test_normalize_drop_params(value, expected):
|
||||
assert normalize_drop_params(value) is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value, expected", [("true", True), ("off", False), (None, False)])
|
||||
def test_drop_params_flag_returns_a_bool_without_a_warning(value, expected, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="drop-params-test"):
|
||||
assert drop_params_flag(value, "LITELLM_DROP_PARAMS", logging.getLogger("drop-params-test")) is expected
|
||||
assert caplog.text == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", ["temperature", "ture", 2])
|
||||
def test_drop_params_flag_treats_non_flag_values_as_off_with_a_warning(value, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="drop-params-test"):
|
||||
assert drop_params_flag(value, "LITELLM_DROP_PARAMS", logging.getLogger("drop-params-test")) is False
|
||||
assert f"LITELLM_DROP_PARAMS={value!r} is not a flag value, treating it as off" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"environ, expected",
|
||||
[
|
||||
({}, False),
|
||||
({"LITELLM_DROP_PARAMS": ""}, False),
|
||||
({"LITELLM_DROP_PARAMS": " "}, False),
|
||||
({"LITELLM_DROP_PARAMS": "true"}, True),
|
||||
({"LITELLM_DROP_PARAMS": " False "}, False),
|
||||
({"LITELLM_DROP_PARAMS": "0"}, False),
|
||||
],
|
||||
)
|
||||
def test_drop_params_env_flag_reads_a_flag_without_a_warning(environ, expected, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="drop-params-test"):
|
||||
assert drop_params_env_flag(environ, logging.getLogger("drop-params-test")) is expected
|
||||
assert caplog.text == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("configured", ["temperature", "temperature,top_p", "enabled"])
|
||||
def test_drop_params_env_flag_keeps_a_non_flag_value_on_with_a_warning(configured, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="drop-params-test"):
|
||||
assert drop_params_env_flag({"LITELLM_DROP_PARAMS": configured}, logging.getLogger("drop-params-test")) is True
|
||||
assert (
|
||||
f"LITELLM_DROP_PARAMS={configured!r} is not a flag value, treating it as on. Set it to true or false"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
class TestIsExpectedClientError:
|
||||
def test_status_ranges(self):
|
||||
from litellm.litellm_core_utils.core_helpers import is_expected_client_error
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from litellm.proxy.management_endpoints.model_management_endpoints import (
|
|||
)
|
||||
from litellm.proxy.utils import PrismaClient
|
||||
from litellm.router import Router
|
||||
from litellm.types.router import Deployment, LiteLLM_Params, updateDeployment
|
||||
from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo, updateDeployment, updateLiteLLMParams
|
||||
|
||||
|
||||
async def _passthrough_row(update_data):
|
||||
|
|
@ -3070,6 +3070,31 @@ class TestUpdateDBModelBlocked:
|
|||
assert "blocked" not in result
|
||||
|
||||
|
||||
class TestUpdateDBModelKeepsLegacyDropParams:
|
||||
def test_partial_patch_keeps_encrypted_string_drop_params(self, monkeypatch):
|
||||
from litellm.proxy.common_utils.encrypt_decrypt_utils import decrypt_value_helper
|
||||
from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model
|
||||
|
||||
monkeypatch.setenv("LITELLM_SALT_KEY", "sk-1234")
|
||||
legacy_row = Deployment(
|
||||
model_name="gpt-5-nano",
|
||||
litellm_params=LiteLLM_Params(
|
||||
model="openai/gpt-5-nano",
|
||||
api_key=encrypt_value_helper(value="sk-old"),
|
||||
drop_params=encrypt_value_helper(value="true"),
|
||||
),
|
||||
model_info=ModelInfo(id="legacy-row"),
|
||||
)
|
||||
|
||||
result = update_db_model(
|
||||
db_model=legacy_row,
|
||||
updated_patch=updateDeployment(litellm_params=updateLiteLLMParams(api_key="sk-new")),
|
||||
)
|
||||
|
||||
stored = json.loads(result["litellm_params"])
|
||||
assert decrypt_value_helper(value=stored["drop_params"], key="drop_params") == "true"
|
||||
|
||||
|
||||
def _build_db_model_with_pricing():
|
||||
"""Wildcard deployment with custom pricing in litellm_params; Deployment.__init__
|
||||
mirrors SPECIAL_MODEL_INFO_PARAMS into model_info, so both blobs hold the rate."""
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import pytest
|
|||
|
||||
import litellm
|
||||
from litellm.proxy._types import CommonProxyErrors
|
||||
from litellm.proxy.common_utils.encrypt_decrypt_utils import encrypt_value_helper
|
||||
from litellm.proxy.proxy_server import (
|
||||
ProxyConfig,
|
||||
_is_remote_module_url,
|
||||
|
|
@ -2428,6 +2429,111 @@ def test_ProxyConfig__add_deployment_resolves_env_refs_on_arbitrary_field(monkey
|
|||
assert deployment.litellm_params.some_future_field == "resolved-custom-value"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"stored_drop_params",
|
||||
["true", "os.environ/DROP_PARAMS_FLAG"],
|
||||
)
|
||||
def test_ProxyConfig__add_deployment_turns_stored_drop_params_string_into_bool(monkeypatch, stored_drop_params):
|
||||
monkeypatch.setenv("LITELLM_SALT_KEY", "sk-1234")
|
||||
monkeypatch.setenv("DROP_PARAMS_FLAG", "true")
|
||||
fake_router = MagicMock()
|
||||
fake_router.upsert_deployment = MagicMock(return_value=True)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", fake_router)
|
||||
pc = ProxyConfig()
|
||||
db_model = SimpleNamespace(
|
||||
model_id="model-1",
|
||||
model_name="gpt-5-nano",
|
||||
model_info={"id": "model-1"},
|
||||
litellm_params={
|
||||
"model": encrypt_value_helper(value="openai/gpt-5-nano"),
|
||||
"drop_params": encrypt_value_helper(value=stored_drop_params),
|
||||
},
|
||||
blocked=False,
|
||||
)
|
||||
|
||||
added = pc._add_deployment(db_models=[db_model])
|
||||
deployment = fake_router.upsert_deployment.call_args.kwargs["deployment"]
|
||||
|
||||
assert added == 1
|
||||
assert deployment.litellm_params.drop_params is True
|
||||
|
||||
|
||||
def test_ProxyConfig__add_deployment_keeps_loading_rows_after_a_non_flag_drop_params(monkeypatch):
|
||||
monkeypatch.setenv("LITELLM_SALT_KEY", "sk-1234")
|
||||
fake_router = MagicMock()
|
||||
fake_router.upsert_deployment = MagicMock(return_value=True)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", fake_router)
|
||||
pc = ProxyConfig()
|
||||
|
||||
def db_model(model_id, drop_params):
|
||||
return SimpleNamespace(
|
||||
model_id=model_id,
|
||||
model_name="gpt-5-nano",
|
||||
model_info={"id": model_id},
|
||||
litellm_params={
|
||||
"model": encrypt_value_helper(value="openai/gpt-5-nano"),
|
||||
"drop_params": encrypt_value_helper(value=drop_params),
|
||||
},
|
||||
blocked=False,
|
||||
)
|
||||
|
||||
added = pc._add_deployment(db_models=[db_model("bad-row", 2), db_model("good-after", "true")])
|
||||
deployments = [call.kwargs["deployment"] for call in fake_router.upsert_deployment.call_args_list]
|
||||
|
||||
assert added == 2
|
||||
assert [d.litellm_params.drop_params for d in deployments] == [None, True]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("configured, expected", [("true", True), ("false", False)])
|
||||
async def test_ProxyConfig_load_config_turns_litellm_settings_drop_params_string_into_bool(
|
||||
tmp_path, monkeypatch, configured, expected
|
||||
):
|
||||
f = tmp_path / "c.yaml"
|
||||
f.write_text(f'model_list: []\nlitellm_settings:\n drop_params: "{configured}"\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", not expected)
|
||||
|
||||
await ProxyConfig().load_config(router=None, config_file_path=str(f))
|
||||
|
||||
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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -246,8 +246,10 @@ async def test_aresponses_keeps_include_obfuscation_in_stream_options():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("drop_params", [True, "true"])
|
||||
async def test_aresponses_request_level_drop_params_drops_bedrock_mantle_service_tier(
|
||||
monkeypatch,
|
||||
drop_params,
|
||||
):
|
||||
"""
|
||||
Request-level drop_params=True (as the proxy injects for agentic CLIs) must
|
||||
|
|
@ -271,7 +273,7 @@ async def test_aresponses_request_level_drop_params_drops_bedrock_mantle_service
|
|||
aws_region_name="us-east-1",
|
||||
input="hi",
|
||||
service_tier="priority",
|
||||
drop_params=True,
|
||||
drop_params=drop_params,
|
||||
)
|
||||
|
||||
mock_post.assert_called_once()
|
||||
|
|
|
|||
33
tests/test_litellm/test_drop_params_env_var.py
Normal file
33
tests/test_litellm/test_drop_params_env_var.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _import_litellm_with(configured: str) -> subprocess.CompletedProcess[str]:
|
||||
return 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,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("configured, expected", [("false", "False"), ("true", "True"), ("", "False")])
|
||||
def test_litellm_drop_params_env_var_is_parsed_as_a_flag(configured, expected):
|
||||
result = _import_litellm_with(configured)
|
||||
|
||||
assert result.stdout.strip() == expected
|
||||
assert "is not a flag value" not in result.stderr
|
||||
|
||||
|
||||
def test_litellm_drop_params_env_var_non_flag_value_stays_on_with_a_warning():
|
||||
result = _import_litellm_with("temperature")
|
||||
|
||||
assert result.stdout.strip() == "True"
|
||||
assert (
|
||||
"LITELLM_DROP_PARAMS='temperature' is not a flag value, treating it as on. Set it to true or false"
|
||||
in result.stderr
|
||||
)
|
||||
|
|
@ -14434,3 +14434,70 @@ async def test_router_max_parallel_requests_slot_released_when_stream_closed_ear
|
|||
|
||||
assert tracker.peak == 1
|
||||
assert tracker.current == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_router_deployment_drop_params_string_true_is_honored(monkeypatch):
|
||||
from litellm import Router
|
||||
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
router = Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "gpt-5-nano",
|
||||
"litellm_params": {
|
||||
"model": "openai/gpt-5-nano",
|
||||
"api_key": "sk-fake",
|
||||
"temperature": 1,
|
||||
"reasoning_effort": "minimal",
|
||||
"drop_params": "true",
|
||||
"mock_response": "Hello, world!",
|
||||
},
|
||||
}
|
||||
],
|
||||
num_retries=0,
|
||||
)
|
||||
|
||||
deployment = router.get_deployment_by_model_group_name(model_group_name="gpt-5-nano")
|
||||
assert deployment is not None
|
||||
assert deployment.litellm_params.drop_params is True
|
||||
|
||||
response = await router.acompletion(
|
||||
model="gpt-5-nano",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
temperature=0.1,
|
||||
)
|
||||
assert response.choices[0].message.content == "Hello, world!"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", ["ture", "enabled"])
|
||||
def test_router_warns_when_a_deployment_drop_params_string_is_not_a_flag(value, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="LiteLLM Router"):
|
||||
router = Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "gpt-5-nano",
|
||||
"litellm_params": {"model": "openai/gpt-5-nano", "api_key": "sk-fake", "drop_params": value},
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
deployment = router.get_deployment_by_model_group_name(model_group_name="gpt-5-nano")
|
||||
assert deployment is not None
|
||||
assert deployment.litellm_params.drop_params == value
|
||||
assert f"model=gpt-5-nano drop_params={value!r} is not a flag value, treating it as unset" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [True, "true", "off", None])
|
||||
def test_router_stays_quiet_when_a_deployment_drop_params_is_a_flag(value, caplog):
|
||||
with caplog.at_level(logging.WARNING, logger="LiteLLM Router"):
|
||||
Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "gpt-5-nano",
|
||||
"litellm_params": {"model": "openai/gpt-5-nano", "api_key": "sk-fake", "drop_params": value},
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert "is not a flag value" not in caplog.text
|
||||
|
|
|
|||
|
|
@ -6094,6 +6094,34 @@ class TestFinalOptionalParamsLineRedaction:
|
|||
assert "'temperature': 0.25" in printed
|
||||
|
||||
|
||||
class TestDropParamsStringCoercion:
|
||||
@pytest.mark.parametrize("drop_params", ["true", "True", True])
|
||||
def test_truthy_drop_params_drops_unsupported_temperature(self, drop_params, monkeypatch):
|
||||
from litellm.utils import get_optional_params
|
||||
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
result = get_optional_params(
|
||||
model="gpt-5-nano",
|
||||
custom_llm_provider="openai",
|
||||
temperature=0.1,
|
||||
drop_params=drop_params,
|
||||
)
|
||||
assert "temperature" not in result
|
||||
|
||||
@pytest.mark.parametrize("drop_params", ["false", False, None])
|
||||
def test_falsy_drop_params_still_raises(self, drop_params, monkeypatch):
|
||||
from litellm.utils import get_optional_params
|
||||
|
||||
monkeypatch.setattr(litellm, "drop_params", False)
|
||||
with pytest.raises(litellm.UnsupportedParamsError):
|
||||
get_optional_params(
|
||||
model="gpt-5-nano",
|
||||
custom_llm_provider="openai",
|
||||
temperature=0.1,
|
||||
drop_params=drop_params,
|
||||
)
|
||||
|
||||
|
||||
def _credential_warnings(caplog: pytest.LogCaptureFixture) -> list[str]:
|
||||
return [record.getMessage() for record in caplog.records if "litellm_credential_name=" in record.getMessage()]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.types.router import (
|
||||
SPECIAL_MODEL_INFO_PARAMS,
|
||||
Deployment,
|
||||
GenericLiteLLMParams,
|
||||
LiteLLM_Params,
|
||||
ModelInfo,
|
||||
)
|
||||
|
|
@ -89,3 +92,33 @@ def test_pricing_strings_are_coerced_to_float():
|
|||
def test_invalid_pricing_is_rejected():
|
||||
with pytest.raises(ValueError, match='validation error for ModelInfo'):
|
||||
ModelInfo(id="x", input_cost_per_token="free")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected",
|
||||
[
|
||||
(True, True),
|
||||
("true", True),
|
||||
(" False ", False),
|
||||
("yes", True),
|
||||
(None, None),
|
||||
("os.environ/DROP_PARAMS", "os.environ/DROP_PARAMS"),
|
||||
("v2:gcm:ciphertext-from-a-pre-fix-row", "v2:gcm:ciphertext-from-a-pre-fix-row"),
|
||||
],
|
||||
)
|
||||
def test_drop_params_coerces_flags_and_keeps_unresolved_strings(value, expected):
|
||||
assert GenericLiteLLMParams(drop_params=value).drop_params == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [2, 2.5, [], {}])
|
||||
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 == ""
|
||||
|
|
|
|||
4
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
4
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -29449,6 +29449,8 @@ export interface components {
|
|||
default_api_key_rpm_limit?: number | null;
|
||||
/** Default Api Key Tpm Limit */
|
||||
default_api_key_tpm_limit?: number | null;
|
||||
/** Drop Params */
|
||||
drop_params?: boolean | string | null;
|
||||
/** Gcs Bucket Name */
|
||||
gcs_bucket_name?: string | null;
|
||||
/** Google Maps Grounding Cost Per Query */
|
||||
|
|
@ -39632,6 +39634,8 @@ export interface components {
|
|||
default_api_key_rpm_limit?: number | null;
|
||||
/** Default Api Key Tpm Limit */
|
||||
default_api_key_tpm_limit?: number | null;
|
||||
/** Drop Params */
|
||||
drop_params?: boolean | string | null;
|
||||
/** Gcs Bucket Name */
|
||||
gcs_bucket_name?: string | null;
|
||||
/** Google Maps Grounding Cost Per Query */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue