mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
fix(logging): key bridged /v1/messages rows on the id the caller received
/v1/messages against a non-Anthropic model answers with the Responses id, but the spend row was built from a fresh ModelResponse, so it landed on a chatcmpl- uuid nobody can look up. Carry that id through the same way the Anthropic branch now does, and make the passthrough spend assertions fail on an empty lookup instead of skipping past it.
This commit is contained in:
parent
3b814179c8
commit
c85da0a75f
3 changed files with 61 additions and 22 deletions
|
|
@ -3888,7 +3888,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
return LiteLLMResponsesTransformationHandler().transform_response(
|
||||
model=self.model,
|
||||
raw_response=result,
|
||||
model_response=litellm.ModelResponse(),
|
||||
model_response=litellm.ModelResponse(id=_provider_response_id(result)),
|
||||
logging_obj=self,
|
||||
request_data={},
|
||||
messages=[],
|
||||
|
|
@ -3903,7 +3903,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
"usage-only ModelResponse to keep the spend_logs row.",
|
||||
str(e),
|
||||
)
|
||||
model_response: Final = litellm.ModelResponse()
|
||||
model_response: Final = litellm.ModelResponse(id=_provider_response_id(result))
|
||||
model_response.model = self.model
|
||||
usage: Final = getattr(result, "usage", None)
|
||||
if usage is not None and ResponseAPILoggingUtils._is_response_api_usage(usage):
|
||||
|
|
|
|||
|
|
@ -84,18 +84,16 @@ async def test_anthropic_basic_completion_with_headers():
|
|||
print("Waiting 10 seconds before retry...")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
# Spend data might be unavailable (auth error, slow DB write, etc.)
|
||||
if (
|
||||
spend_data is None
|
||||
or not isinstance(spend_data, list)
|
||||
or len(spend_data) == 0
|
||||
or not isinstance(spend_data[0], dict)
|
||||
or "request_id" not in spend_data[0]
|
||||
):
|
||||
print(f"Spend data not available or is error response: {spend_data}")
|
||||
print("Skipping spend assertions (DB write may be slow in CI)")
|
||||
if not isinstance(spend_data, list):
|
||||
print(f"Spend endpoint answered with an error response: {spend_data}")
|
||||
print("Skipping spend assertions (spend logs unreachable in CI)")
|
||||
return
|
||||
|
||||
assert spend_data, (
|
||||
f"GET /spend/logs?request_id={anthropic_message_id} found no row for the id "
|
||||
"the caller received"
|
||||
)
|
||||
|
||||
log_entry = spend_data[0]
|
||||
|
||||
# Basic existence checks
|
||||
|
|
@ -255,18 +253,16 @@ async def test_anthropic_streaming_with_headers():
|
|||
print("Waiting 10 seconds before retry...")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
# Spend data might be unavailable (auth error, slow DB write, etc.)
|
||||
if (
|
||||
spend_data is None
|
||||
or not isinstance(spend_data, list)
|
||||
or len(spend_data) == 0
|
||||
or not isinstance(spend_data[0], dict)
|
||||
or "request_id" not in spend_data[0]
|
||||
):
|
||||
print(f"Spend data not available or is error response: {spend_data}")
|
||||
print("Skipping spend assertions (DB write may be slow in CI)")
|
||||
if not isinstance(spend_data, list):
|
||||
print(f"Spend endpoint answered with an error response: {spend_data}")
|
||||
print("Skipping spend assertions (spend logs unreachable in CI)")
|
||||
return
|
||||
|
||||
assert spend_data, (
|
||||
f"GET /spend/logs?request_id={anthropic_message_id} found no row for the id "
|
||||
"the caller received"
|
||||
)
|
||||
|
||||
log_entry = spend_data[0]
|
||||
|
||||
# Basic existence checks
|
||||
|
|
|
|||
|
|
@ -4186,3 +4186,46 @@ def test_spend_log_request_id_for_chat_completions_is_untouched():
|
|||
)
|
||||
== "chatcmpl-EJvWIw3DAhuKYuwp3jJI4Pnhp2vjv"
|
||||
)
|
||||
|
||||
|
||||
def test_spend_log_request_id_is_the_response_id_a_bridged_messages_caller_received():
|
||||
"""
|
||||
/v1/messages against a non-Anthropic model answers with the Responses id the caller then
|
||||
looks their row up by, so the row must not fall back to a fresh chatcmpl- uuid.
|
||||
"""
|
||||
from litellm.types.llms.openai import ResponseAPIUsage, ResponsesAPIResponse
|
||||
|
||||
logging_obj = _anthropic_messages_logging_obj(stream=False)
|
||||
bridged_response = ResponsesAPIResponse(
|
||||
id="resp_01Lit6806Bridged",
|
||||
object="response",
|
||||
created_at=1767225600,
|
||||
model="gpt-5.6",
|
||||
status="completed",
|
||||
output=[
|
||||
{
|
||||
"id": "msg_bridged_output",
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"status": "completed",
|
||||
"content": [{"type": "output_text", "text": "delta", "annotations": []}],
|
||||
}
|
||||
],
|
||||
usage=ResponseAPIUsage(input_tokens=13, output_tokens=5, total_tokens=18),
|
||||
)
|
||||
|
||||
logged_response = logging_obj._handle_anthropic_messages_response_logging(result=bridged_response)
|
||||
|
||||
assert logged_response.id == "resp_01Lit6806Bridged"
|
||||
assert (
|
||||
_spend_log_request_id(
|
||||
response_obj=logged_response,
|
||||
kwargs={
|
||||
"call_type": "anthropic_messages",
|
||||
"model": "gpt-5.6",
|
||||
"litellm_call_id": "6806cafe-0000-4000-8000-000000000003",
|
||||
"litellm_params": {"metadata": {"user_api_key": "test-key"}},
|
||||
},
|
||||
)
|
||||
== "resp_01Lit6806Bridged"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue