This commit is contained in:
mac146 2026-11-06 15:50:44 -05:00 • committed by GitHub
commit f15677ef78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 57 additions and 3 deletions

View file

@ -119,12 +119,14 @@ def _is_response_cache_excluded(model: str | None, kwargs: Mapping[str, object])
def _is_chat_completion_cached_dict(cached_result: dict) -> bool:
cached_id: Final = cached_result.get("id")
if isinstance(cached_id, str) and cached_id.startswith("chatcmpl"):
return True
# `object` is checked before the id: the Responses to chat completions bridge
# stores Responses API objects (`object: "response"`) under a `chatcmpl-` id.
obj: Final = cached_result.get("object")
if isinstance(obj, str):
return obj.startswith("chat.completion")
cached_id: Final = cached_result.get("id")
if isinstance(cached_id, str) and cached_id.startswith("chatcmpl"):
return True
return "choices" in cached_result

View file

@ -1412,6 +1412,12 @@ def test_is_chat_completion_cached_dict():
assert not _is_chat_completion_cached_dict(
{"id": "resp_abc", "object": "response", "output": []}
)
# The bridge stores a Responses API object under a chatcmpl- id; `object` decides.
assert not _is_chat_completion_cached_dict(
{"id": "chatcmpl-bridge", "object": "response", "output": []}
)
# No `object` at all: the chatcmpl- id still marks a chat completion.
assert _is_chat_completion_cached_dict({"id": "chatcmpl-abc"})
def test_convert_cached_aresponses_bridge_chat_completion_stream():
@ -2097,6 +2103,52 @@ def test_convert_cached_responses_legacy_nonstream_path():
assert result.id == "resp_legacy_nonstream"
def test_convert_cached_responses_bridge_responses_object_keeps_chatcmpl_id():
"""
Responses to chat completions bridge (for example anthropic/): the stored object is a
Responses API response whose id is the bridge's chatcmpl- id. The cache hit must replay it
as a Responses API response, not rebuild it as a chat completion without `choices`.
"""
from litellm import responses
from litellm.types.llms.openai import ResponsesAPIResponse
from litellm.types.utils import CallTypes
caching_handler = LLMCachingHandler(
original_function=responses, request_kwargs={}, start_time=datetime.now()
)
cached_result = {
"id": "chatcmpl-bridge-responses-object",
"created_at": int(time.time()),
"status": "completed",
"model": "claude-sonnet-4-5",
"object": "response",
"output": [
{
"type": "message",
"id": "msg_bridge",
"status": "completed",
"role": "assistant",
"content": [
{"type": "output_text", "text": "hello", "annotations": []}
],
}
],
}
result = caching_handler._convert_cached_result_to_model_response(
cached_result=cached_result,
call_type=CallTypes.responses.value,
kwargs={"model": "anthropic/claude-sonnet-4-5", "input": "hi", "stream": False},
logging_obj=_build_logging_obj(CallTypes.responses.value, stream=False),
model="anthropic/claude-sonnet-4-5",
args=(),
)
assert isinstance(result, ResponsesAPIResponse)
assert result.id == "chatcmpl-bridge-responses-object"
assert result.output_text == "hello"
def test_convert_cached_responses_legacy_stream_path():
"""Genuine ResponsesAPIResponse dict (no chatcmpl/choices) on stream falls through legacy path."""
from litellm import responses