mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-24 00:52:24 +00:00
fix(responses): guard against None cache_control on content blocks
This commit is contained in:
parent
4b2a436317
commit
4a307e6759
2 changed files with 40 additions and 6 deletions
|
|
@ -1158,7 +1158,7 @@ class LiteLLMCompletionResponsesConfig:
|
|||
file_dict["file_data"] = item["file_data"]
|
||||
|
||||
new_item: dict[str, Any] = {"type": "file", "file": file_dict}
|
||||
if "cache_control" in item:
|
||||
if item.get("cache_control") is not None:
|
||||
new_item["cache_control"] = item["cache_control"]
|
||||
return new_item
|
||||
|
||||
|
|
@ -1180,16 +1180,15 @@ class LiteLLMCompletionResponsesConfig:
|
|||
"""
|
||||
Normalize a Responses API object (Pydantic model or custom class) to a dictionary
|
||||
"""
|
||||
if hasattr(item, "model_dump"):
|
||||
if hasattr(item, "model_dump"):
|
||||
try:
|
||||
return item.model_dump(exclude_none=True)
|
||||
except Exception: # noqa: BLE001 # fallback if custom model_dump does not accept exclude_none
|
||||
except TypeError:
|
||||
return item.model_dump()
|
||||
elif hasattr(item, "dict"):
|
||||
try:
|
||||
return item.dict(exclude_none=True)
|
||||
except Exception: # noqa: BLE001 # fallback if custom dict does not accept exclude_none
|
||||
except TypeError:
|
||||
return item.dict()
|
||||
|
||||
target_attrs = (
|
||||
|
|
@ -1247,7 +1246,11 @@ class LiteLLMCompletionResponsesConfig:
|
|||
elif item.get("type") == "input_image":
|
||||
image_block = {
|
||||
**LiteLLMCompletionResponsesConfig._transform_input_image_item_to_image_item(item),
|
||||
**({"cache_control": item["cache_control"]} if "cache_control" in item else {}),
|
||||
**(
|
||||
{"cache_control": item["cache_control"]}
|
||||
if item.get("cache_control") is not None
|
||||
else {}
|
||||
),
|
||||
}
|
||||
content_list.append(image_block)
|
||||
else:
|
||||
|
|
@ -1260,7 +1263,11 @@ class LiteLLMCompletionResponsesConfig:
|
|||
item.get("type") or "text"
|
||||
),
|
||||
"text": text_value,
|
||||
**({"cache_control": item["cache_control"]} if "cache_control" in item else {}),
|
||||
**(
|
||||
{"cache_control": item["cache_control"]}
|
||||
if item.get("cache_control") is not None
|
||||
else {}
|
||||
),
|
||||
}
|
||||
content_list.append(content_block)
|
||||
return content_list
|
||||
|
|
|
|||
|
|
@ -2635,6 +2635,33 @@ class TestCacheControlPreservation:
|
|||
)
|
||||
assert messages == [{"role": "user", "content": "hello", "cache_control": {"type": "ephemeral"}}]
|
||||
|
||||
def test_none_cache_control_omitted_from_content_blocks(self):
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
class MockContentItem(BaseModel):
|
||||
type: str = "text"
|
||||
text: str = "hello world"
|
||||
cache_control: Optional[dict] = None
|
||||
|
||||
item = MockContentItem()
|
||||
result = LiteLLMCompletionResponsesConfig._transform_responses_api_content_to_chat_completion_content([item])
|
||||
assert isinstance(result, list)
|
||||
assert len(result) == 1
|
||||
assert "cache_control" not in result[0]
|
||||
|
||||
dict_item = {"type": "text", "text": "hello", "cache_control": None}
|
||||
result_dict = LiteLLMCompletionResponsesConfig._transform_responses_api_content_to_chat_completion_content([dict_item])
|
||||
assert isinstance(result_dict, list)
|
||||
assert len(result_dict) == 1
|
||||
assert "cache_control" not in result_dict[0]
|
||||
|
||||
image_item = {"type": "input_image", "image_url": "https://example.com/a.png", "cache_control": None}
|
||||
result_img = LiteLLMCompletionResponsesConfig._transform_responses_api_content_to_chat_completion_content([image_item])
|
||||
assert isinstance(result_img, list)
|
||||
assert len(result_img) == 1
|
||||
assert "cache_control" not in result_img[0]
|
||||
|
||||
def test_tool_call_output_as_custom_object(self):
|
||||
"""Test _transform_responses_api_tool_call_output_to_chat_completion_message with a custom object."""
|
||||
class MockToolCallOutput:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue