mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-11 22:51:28 +00:00
fix(proxy): log prompt-shaped model strings on pass-through failures under the placeholder model
This commit is contained in:
parent
dbcb10c57d
commit
368de5df68
3 changed files with 39 additions and 12 deletions
|
|
@ -2000,6 +2000,7 @@ NON_INFERENCE_CALL_TYPES: Final[frozenset[str]] = frozenset(
|
|||
)
|
||||
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL: Final[str] = "unknown-model"
|
||||
MAX_SPEND_LOG_MODEL_NAME_LENGTH: Final[int] = 256
|
||||
|
||||
# PTU reservation rollup writes rows to LiteLLM_DailyTeamSpend with this
|
||||
# sentinel api_key so PTU flat cost stays distinguishable from real per-request
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from litellm.constants import (
|
|||
LITELLM_TRUNCATION_DB_SAFEGUARD_NOTE,
|
||||
LITTELM_CLI_SERVICE_ACCOUNT_NAME,
|
||||
LITTELM_INTERNAL_HEALTH_SERVICE_ACCOUNT_NAME,
|
||||
MAX_SPEND_LOG_MODEL_NAME_LENGTH,
|
||||
REDACTED_BY_LITELM_STRING,
|
||||
SESSION_ID_OMITTED_METADATA_KEY,
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL,
|
||||
|
|
@ -333,6 +334,10 @@ def _sl_attribution_fallback(
|
|||
return standard_logging_payload.get(field) or ""
|
||||
|
||||
|
||||
def _looks_like_model_name(model: str) -> bool:
|
||||
return len(model) <= MAX_SPEND_LOG_MODEL_NAME_LENGTH and not any(char.isspace() for char in model)
|
||||
|
||||
|
||||
def get_logging_payload(kwargs, response_obj, start_time, end_time) -> SpendLogsPayload:
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
|
|
@ -435,11 +440,13 @@ def get_logging_payload(kwargs, response_obj, start_time, end_time) -> SpendLogs
|
|||
or None
|
||||
)
|
||||
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, custom_llm_provider, metadata or {})
|
||||
model_name: Final = (
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL
|
||||
if rejected_as_unknown_model
|
||||
else (standard_logging_payload.get("model") if standard_logging_payload is not None else None)
|
||||
or reconstruct_model_name(raw_model, custom_llm_provider, metadata or {})
|
||||
if rejected_as_unknown_model or not _looks_like_model_name(resolved_model)
|
||||
else resolved_model
|
||||
)
|
||||
litellm_call_id: Final = cast(
|
||||
str | None,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import asyncio
|
||||
import datetime
|
||||
import json
|
||||
from datetime import timezone
|
||||
from collections.abc import Mapping
|
||||
from datetime import timezone
|
||||
from typing import Any, Final, cast
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
|
|
@ -15,12 +15,13 @@ from litellm.constants import (
|
|||
LITELLM_TRUNCATION_DB_SAFEGUARD_NOTE,
|
||||
LITTELM_CLI_SERVICE_ACCOUNT_NAME,
|
||||
LITTELM_INTERNAL_HEALTH_SERVICE_ACCOUNT_NAME,
|
||||
MAX_SPEND_LOG_MODEL_NAME_LENGTH,
|
||||
REDACTED_BY_LITELM_STRING,
|
||||
SESSION_ID_OMITTED_METADATA_KEY,
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL,
|
||||
)
|
||||
from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
from litellm.proxy._types import SpendLogsPayload, UserAPIKeyAuth
|
||||
from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup
|
||||
from litellm.proxy.route_llm_request import ProxyModelNotFoundError
|
||||
from litellm.proxy.spend_tracking.spend_tracking_utils import (
|
||||
|
|
@ -41,7 +42,6 @@ from litellm.proxy.spend_tracking.spend_tracking_utils import (
|
|||
get_logging_payload,
|
||||
get_spend_logs_id,
|
||||
)
|
||||
from litellm.proxy._types import SpendLogsPayload
|
||||
from litellm.proxy.utils import hash_token
|
||||
from litellm.types.utils import (
|
||||
StandardLoggingHiddenParams,
|
||||
|
|
@ -927,21 +927,40 @@ def test_safe_dumps_complex_metadata_like_object():
|
|||
_RAW_MODEL_WITH_PROMPT: Final = "opus-4.6 Please summarize my medical records\nPatient has diabetes"
|
||||
|
||||
|
||||
_BEDROCK_INFERENCE_PROFILE_ARN: Final = (
|
||||
"arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/claude-sonnet-4-5"
|
||||
)
|
||||
_OVERLONG_MODEL: Final = "m" * (MAX_SPEND_LOG_MODEL_NAME_LENGTH + 1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("rejection", "expected_model"),
|
||||
("requested_model", "failure", "expected_model"),
|
||||
[
|
||||
(
|
||||
_RAW_MODEL_WITH_PROMPT,
|
||||
ProxyModelNotFoundError(route="acompletion", model_name=_RAW_MODEL_WITH_PROMPT),
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL,
|
||||
),
|
||||
(ValueError("provider timed out"), _RAW_MODEL_WITH_PROMPT),
|
||||
(
|
||||
_RAW_MODEL_WITH_PROMPT,
|
||||
ValueError("Upstream passthrough request failed with status 404"),
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL,
|
||||
),
|
||||
(_OVERLONG_MODEL, ValueError("provider timed out"), UNKNOWN_MODEL_SPEND_LOG_MODEL),
|
||||
(
|
||||
"gpt-5.2",
|
||||
ProxyModelNotFoundError(route="acompletion", model_name="gpt-5.2"),
|
||||
UNKNOWN_MODEL_SPEND_LOG_MODEL,
|
||||
),
|
||||
("gpt-5.2", ValueError("provider timed out"), "gpt-5.2"),
|
||||
(_BEDROCK_INFERENCE_PROFILE_ARN, ValueError("provider timed out"), _BEDROCK_INFERENCE_PROFILE_ARN),
|
||||
],
|
||||
)
|
||||
def test_get_logging_payload_replaces_model_only_when_router_rejected_it_as_unknown(
|
||||
rejection: Exception, expected_model: str
|
||||
def test_get_logging_payload_replaces_rejected_or_prompt_shaped_models_with_the_placeholder(
|
||||
requested_model: str, failure: Exception, expected_model: str
|
||||
):
|
||||
kwargs: Final = {
|
||||
"model": _RAW_MODEL_WITH_PROMPT,
|
||||
"model": requested_model,
|
||||
"messages": [{"role": "user", "content": "hi"}],
|
||||
"call_type": "acompletion",
|
||||
"litellm_params": {"metadata": {"user_api_key": "sk-test", "status": "failure"}},
|
||||
|
|
@ -949,7 +968,7 @@ def test_get_logging_payload_replaces_model_only_when_router_rejected_it_as_unkn
|
|||
|
||||
payload: Final = get_logging_payload(
|
||||
kwargs=kwargs,
|
||||
response_obj=rejection,
|
||||
response_obj=failure,
|
||||
start_time=datetime.datetime.now(timezone.utc),
|
||||
end_time=datetime.datetime.now(timezone.utc),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue