fix(anthropic): prevent crash with cache_control and empty message content (#34025)

This commit is contained in:
Viktor Taranenko
2025-12-13 01:32:11 +03:00
committed by GitHub
parent 20b8342fdf
commit 470160cf81
2 changed files with 39 additions and 21 deletions

View File

@@ -1008,27 +1008,27 @@ class ChatAnthropic(BaseChatModel):
system, formatted_messages = _format_messages(messages) system, formatted_messages = _format_messages(messages)
# If cache_control is provided in kwargs, add it to last message # If cache_control is provided in kwargs, add it to the last message with
# and content block. # content (Anthropic requires cache_control to be nested within a message
if "cache_control" in kwargs and formatted_messages: # block).
if isinstance(formatted_messages[-1]["content"], list): cache_control = kwargs.pop("cache_control", None)
formatted_messages[-1]["content"][-1]["cache_control"] = kwargs.pop( if cache_control and formatted_messages:
"cache_control" for formatted_message in reversed(formatted_messages):
) content = formatted_message.get("content")
elif isinstance(formatted_messages[-1]["content"], str): if isinstance(content, list) and content:
formatted_messages[-1]["content"] = [ content[-1]["cache_control"] = cache_control
{ break
"type": "text", if isinstance(content, str):
"text": formatted_messages[-1]["content"], formatted_message["content"] = [
"cache_control": kwargs.pop("cache_control"), {
} "type": "text",
] "text": content,
else: "cache_control": cache_control,
pass }
]
# If cache_control remains in kwargs, it would be passed as a top-level param break
# to the API, but Anthropic expects it nested within a message # If we didn't find a message with content we silently drop the control.
_ = kwargs.pop("cache_control", None) # Anthropic would reject a payload with empty content blocks.
payload = { payload = {
"model": self.model, "model": self.model,

View File

@@ -1505,6 +1505,7 @@ def test_cache_control_kwarg() -> None:
], ],
}, },
] ]
assert isinstance(messages[-1].content, str) # test no mutation
messages = [ messages = [
HumanMessage("foo"), HumanMessage("foo"),
@@ -1528,6 +1529,23 @@ def test_cache_control_kwarg() -> None:
], ],
}, },
] ]
assert "cache_control" not in messages[-1].content[-1] # test no mutation
def test_cache_control_kwarg_skips_empty_messages() -> None:
llm = ChatAnthropic(model=MODEL_NAME)
messages = [HumanMessage("foo"), AIMessage(content=[])]
payload = llm._get_request_payload(messages, cache_control={"type": "ephemeral"})
assert payload["messages"] == [
{
"role": "user",
"content": [
{"type": "text", "text": "foo", "cache_control": {"type": "ephemeral"}}
],
},
{"role": "assistant", "content": []},
]
def test_context_management_in_payload() -> None: def test_context_management_in_payload() -> None: