mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
Merge remote-tracking branch 'origin/main' into litellm_team_member_temp_budget_increase
This commit is contained in:
commit
42429500be
5 changed files with 68 additions and 9 deletions
|
|
@ -1937,6 +1937,14 @@ class ProxyBaseLLMRequestProcessing:
|
|||
) -> tuple[dict, LiteLLMLoggingObj]:
|
||||
start_time: Final = datetime.now() # start before calling guardrail hooks
|
||||
|
||||
requested_model: Final = self.data.get("model")
|
||||
if requested_model is not None and not isinstance(requested_model, str):
|
||||
raise ProxyException(
|
||||
message="'model' must be a string.",
|
||||
type=ProxyErrorTypes.bad_request_error,
|
||||
param="model",
|
||||
code=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
self.data = await add_litellm_data_to_request(
|
||||
data=self.data,
|
||||
request=request,
|
||||
|
|
|
|||
|
|
@ -485,10 +485,13 @@ def get_logging_payload(
|
|||
or None
|
||||
)
|
||||
custom_llm_provider: Final = logged_provider or _model_group_provider(_model_group, llm_router)
|
||||
raw_model: Final = cast(str, kwargs.get("model") or "")
|
||||
resolved_model: Final = (
|
||||
standard_logging_payload.get("model") if standard_logging_payload is not None else None
|
||||
) or reconstruct_model_name(raw_model, logged_provider, metadata or {})
|
||||
requested_model: Final = cast(object, kwargs.get("model"))
|
||||
raw_model: Final = requested_model if isinstance(requested_model, str) else ""
|
||||
model_is_malformed: Final = requested_model is not None and not isinstance(requested_model, str)
|
||||
logged_model: Final = standard_logging_payload.get("model") if standard_logging_payload is not None else None
|
||||
resolved_model: Final = (logged_model if isinstance(logged_model, str) else None) or reconstruct_model_name(
|
||||
raw_model, logged_provider, metadata or {}
|
||||
)
|
||||
failed_with_prompt_shaped_model: Final = (
|
||||
_get_status_for_spend_log(metadata=metadata) == "failure"
|
||||
and not _model_group
|
||||
|
|
@ -496,7 +499,7 @@ def get_logging_payload(
|
|||
)
|
||||
model_name: Final = (
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL
|
||||
if rejected_as_unknown_model or failed_with_prompt_shaped_model
|
||||
if rejected_as_unknown_model or failed_with_prompt_shaped_model or model_is_malformed
|
||||
else resolved_model
|
||||
)
|
||||
litellm_call_id: Final = cast(
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,27 @@ def test_get_logging_payload_replaces_rejected_or_prompt_shaped_models_with_the_
|
|||
assert payload["model"] == expected_model
|
||||
|
||||
|
||||
@pytest.mark.parametrize("requested_model", [{"bad": "value"}, ["gpt-5.2"], 1])
|
||||
def test_get_logging_payload_replaces_a_non_string_model_with_the_placeholder(
|
||||
requested_model: dict[str, str] | list[str] | int,
|
||||
):
|
||||
kwargs: Final = {
|
||||
"model": requested_model,
|
||||
"messages": [{"role": "user", "content": "hi"}],
|
||||
"call_type": "acompletion",
|
||||
"litellm_params": {"metadata": {"user_api_key": "sk-test", "status": "failure"}},
|
||||
}
|
||||
|
||||
payload: Final = get_logging_payload(
|
||||
kwargs=kwargs,
|
||||
response_obj=ValueError("model must be a string"),
|
||||
start_time=datetime.datetime.now(timezone.utc),
|
||||
end_time=datetime.datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
assert payload["model"] == UNKNOWN_MODEL_SPEND_LOG_MODEL
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("metadata", "response_obj"),
|
||||
[
|
||||
|
|
|
|||
|
|
@ -327,6 +327,35 @@ class TestProxyBaseLLMRequestProcessing:
|
|||
pytest.fail("litellm_call_id is not a valid UUID")
|
||||
assert data_passed["litellm_call_id"] == returned_data["litellm_call_id"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("requested_model", [{"bad": "value"}, ["gpt-5.2"], 1])
|
||||
async def test_common_processing_pre_call_logic_rejects_a_non_string_model_with_400(
|
||||
self, monkeypatch, requested_model: dict[str, str] | list[str] | int
|
||||
):
|
||||
processing_obj = ProxyBaseLLMRequestProcessing(
|
||||
data={"model": requested_model, "messages": [{"role": "user", "content": "hi"}]}
|
||||
)
|
||||
mock_request = MagicMock(spec=Request)
|
||||
mock_request.headers = {}
|
||||
add_litellm_data_to_request = AsyncMock()
|
||||
monkeypatch.setattr(
|
||||
litellm.proxy.common_request_processing, "add_litellm_data_to_request", add_litellm_data_to_request
|
||||
)
|
||||
|
||||
with pytest.raises(ProxyException) as exc_info:
|
||||
await processing_obj.common_processing_pre_call_logic(
|
||||
request=mock_request,
|
||||
general_settings={},
|
||||
user_api_key_dict=MagicMock(spec=UserAPIKeyAuth),
|
||||
proxy_logging_obj=MagicMock(spec=ProxyLogging),
|
||||
proxy_config=MagicMock(spec=ProxyConfig),
|
||||
route_type="acompletion",
|
||||
)
|
||||
|
||||
assert exc_info.value.code == str(status.HTTP_400_BAD_REQUEST)
|
||||
assert exc_info.value.param == "model"
|
||||
add_litellm_data_to_request.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_common_processing_pre_call_logic_refreshes_proxy_server_request_body_after_guardrails(
|
||||
self, monkeypatch
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ def _successor(info: dict[str, object]) -> str | None:
|
|||
return successor if isinstance(successor, str) else None
|
||||
|
||||
|
||||
def test_together_successor_metadata_points_at_live_models(cost_map: CostMap):
|
||||
def test_together_successor_metadata_points_at_known_models(cost_map: CostMap):
|
||||
successors = {
|
||||
model: successor
|
||||
for model, info in cost_map.items()
|
||||
|
|
@ -103,9 +103,7 @@ def test_together_successor_metadata_points_at_live_models(cost_map: CostMap):
|
|||
}
|
||||
assert len(successors) >= 10
|
||||
for model, successor in successors.items():
|
||||
target = cost_map.get(successor)
|
||||
assert target is not None, f"{model} names successor {successor} that is not in the map"
|
||||
assert "deprecation_date" not in target, f"{model} names deprecated successor {successor}"
|
||||
assert successor in cost_map, f"{model} names successor {successor} that is not in the map"
|
||||
|
||||
|
||||
def test_together_backup_cost_map_in_sync(cost_map: CostMap):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue