(fix) Anthropic pass through cost tracking (#8874)

* fix _create_anthropic_response_logging_payload

* fix - pass through don't create standard logging payload

* fix logged key hash

* test_init_kwargs_for_pass_through_endpoint_basic

* test_unit_test_anthropic_pass_through

* fix anthropic pass through logging handler
This commit is contained in:
Ishaan Jaff 2025-02-27 15:42:43 -08:00 committed by GitHub
parent ff553fedf8
commit 24df2331ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 24 additions and 45 deletions

View file

@ -7,9 +7,6 @@ import httpx
import litellm import litellm
from litellm._logging import verbose_proxy_logger from litellm._logging import verbose_proxy_logger
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.litellm_core_utils.litellm_logging import (
get_standard_logging_object_payload,
)
from litellm.llms.anthropic.chat.handler import ( from litellm.llms.anthropic.chat.handler import (
ModelResponseIterator as AnthropicModelResponseIterator, ModelResponseIterator as AnthropicModelResponseIterator,
) )
@ -116,22 +113,11 @@ class AnthropicPassthroughLoggingHandler:
{"proxy_server_request": {"body": {"user": user}}} {"proxy_server_request": {"body": {"user": user}}}
) )
# Make standard logging object for Anthropic
standard_logging_object = get_standard_logging_object_payload(
kwargs=kwargs,
init_response_obj=litellm_model_response,
start_time=start_time,
end_time=end_time,
logging_obj=logging_obj,
status="success",
)
# pretty print standard logging object # pretty print standard logging object
verbose_proxy_logger.debug( verbose_proxy_logger.debug(
"standard_logging_object= %s", "kwargs= %s",
json.dumps(standard_logging_object, indent=4), json.dumps(kwargs, indent=4, default=str),
) )
kwargs["standard_logging_object"] = standard_logging_object
# set litellm_call_id to logging response object # set litellm_call_id to logging response object
litellm_model_response.id = logging_obj.litellm_call_id litellm_model_response.id = logging_obj.litellm_call_id

View file

@ -8,9 +8,6 @@ import httpx
import litellm import litellm
from litellm._logging import verbose_proxy_logger from litellm._logging import verbose_proxy_logger
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.litellm_core_utils.litellm_logging import (
get_standard_logging_object_payload,
)
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import ( from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
ModelResponseIterator as VertexModelResponseIterator, ModelResponseIterator as VertexModelResponseIterator,
) )
@ -236,21 +233,8 @@ class VertexPassthroughLoggingHandler:
kwargs["response_cost"] = response_cost kwargs["response_cost"] = response_cost
kwargs["model"] = model kwargs["model"] = model
# Make standard logging object for Vertex AI
standard_logging_object = get_standard_logging_object_payload(
kwargs=kwargs,
init_response_obj=litellm_model_response,
start_time=start_time,
end_time=end_time,
logging_obj=logging_obj,
status="success",
)
# pretty print standard logging object # pretty print standard logging object
verbose_proxy_logger.debug( verbose_proxy_logger.debug("kwargs= %s", json.dumps(kwargs, indent=4))
"standard_logging_object= %s", json.dumps(standard_logging_object, indent=4)
)
kwargs["standard_logging_object"] = standard_logging_object
# set litellm_call_id to logging response object # set litellm_call_id to logging response object
litellm_model_response.id = logging_obj.litellm_call_id litellm_model_response.id = logging_obj.litellm_call_id

View file

@ -4,9 +4,9 @@ import json
from base64 import b64encode from base64 import b64encode
from datetime import datetime from datetime import datetime
from typing import List, Optional from typing import List, Optional
from urllib.parse import urlparse
import httpx import httpx
from urllib.parse import urlparse
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
@ -26,6 +26,7 @@ from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.proxy.common_utils.http_parsing_utils import _read_request_body from litellm.proxy.common_utils.http_parsing_utils import _read_request_body
from litellm.secret_managers.main import get_secret_str from litellm.secret_managers.main import get_secret_str
from litellm.types.llms.custom_http import httpxSpecialProvider from litellm.types.llms.custom_http import httpxSpecialProvider
from litellm.types.utils import StandardLoggingUserAPIKeyMetadata
from .streaming_handler import PassThroughStreamingHandler from .streaming_handler import PassThroughStreamingHandler
from .success_handler import PassThroughEndpointLogging from .success_handler import PassThroughEndpointLogging
@ -607,12 +608,19 @@ def _init_kwargs_for_pass_through_endpoint(
) -> dict: ) -> dict:
_parsed_body = _parsed_body or {} _parsed_body = _parsed_body or {}
_litellm_metadata: Optional[dict] = _parsed_body.pop("litellm_metadata", None) _litellm_metadata: Optional[dict] = _parsed_body.pop("litellm_metadata", None)
_metadata = { _metadata = dict(
"user_api_key": user_api_key_dict.api_key, StandardLoggingUserAPIKeyMetadata(
"user_api_key_user_id": user_api_key_dict.user_id, user_api_key_hash=user_api_key_dict.api_key,
"user_api_key_team_id": user_api_key_dict.team_id, user_api_key_alias=user_api_key_dict.key_alias,
"user_api_key_end_user_id": user_api_key_dict.end_user_id, user_api_key_user_email=user_api_key_dict.user_email,
} user_api_key_user_id=user_api_key_dict.user_id,
user_api_key_team_id=user_api_key_dict.team_id,
user_api_key_org_id=user_api_key_dict.org_id,
user_api_key_team_alias=user_api_key_dict.team_alias,
user_api_key_end_user_id=user_api_key_dict.end_user_id,
)
)
_metadata["user_api_key"] = user_api_key_dict.api_key
if _litellm_metadata: if _litellm_metadata:
_metadata.update(_litellm_metadata) _metadata.update(_litellm_metadata)

View file

@ -124,10 +124,16 @@ def test_init_kwargs_for_pass_through_endpoint_basic(
# Check metadata # Check metadata
expected_metadata = { expected_metadata = {
"user_api_key": "test-key", "user_api_key": "test-key",
"user_api_key_hash": "test-key",
"user_api_key_alias": None,
"user_api_key_user_email": None,
"user_api_key_user_id": "test-user", "user_api_key_user_id": "test-user",
"user_api_key_team_id": "test-team", "user_api_key_team_id": "test-team",
"user_api_key_org_id": None,
"user_api_key_team_alias": None,
"user_api_key_end_user_id": "test-user", "user_api_key_end_user_id": "test-user",
} }
assert result["litellm_params"]["metadata"] == expected_metadata assert result["litellm_params"]["metadata"] == expected_metadata

View file

@ -200,11 +200,6 @@ def test_create_anthropic_response_logging_payload(mock_logging_obj, metadata_pa
assert isinstance(result, dict) assert isinstance(result, dict)
assert "model" in result assert "model" in result
assert "response_cost" in result assert "response_cost" in result
assert "standard_logging_object" in result
if metadata_params:
assert "test" == result["standard_logging_object"]["end_user"]
else:
assert "" == result["standard_logging_object"]["end_user"]
@pytest.mark.parametrize( @pytest.mark.parametrize(