test(anthropic): pin tool_result cache_control placement on the /v1/messages bridge

With enable_anthropic_prompt_caching on, a /v1/messages request routed through
the chat completions bridge got the trailing-turn breakpoint nested inside
tool_result.content. Cover both the hook-injected and the client-sent marker.
This commit is contained in:
lkshrk 2026-10-10 02:46:15 +02:00
parent bfde0fcc59
commit 8e34913d88
No known key found for this signature in database

View file

@ -1685,3 +1685,47 @@ async def test_anthropic_messages_forwards_safeguards_and_dangerous_tool_use_bet
assert "anthropic_beta" not in captured["body"]
assert captured["anthropic-beta"].split(",").count("dangerous-tool-use-2026-09-03") == 1
assert response["safeguard_results"] == safeguard_results
@pytest.mark.asyncio
@pytest.mark.parametrize("client_marker", [False, True])
async def test_messages_bridge_keeps_tool_result_cache_control_on_tool_result(monkeypatch, client_marker):
from litellm.llms.anthropic.pass_through.adapters.handler import (
LiteLLMMessagesToCompletionTransformationHandler,
)
monkeypatch.setattr(litellm, "enable_anthropic_prompt_caching", True)
captured = {}
async def fake_send(self, request, **kwargs):
captured["body"] = json.loads(request.content)
raise httpx.ConnectError("cut at the wire", request=request)
tool_result: dict[str, Any] = {
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": [{"type": "text", "text": "file1"}, {"type": "text", "text": "file2"}],
}
if client_marker:
tool_result["cache_control"] = {"type": "ephemeral"}
with (
patch.object(httpx.AsyncClient, "send", fake_send),
pytest.raises(litellm.exceptions.InternalServerError),
):
await LiteLLMMessagesToCompletionTransformationHandler.async_anthropic_messages_handler(
max_tokens=8,
messages=[
{"role": "user", "content": [{"type": "text", "text": "list files"}]},
{"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_01", "name": "ls", "input": {}}]},
{"role": "user", "content": [tool_result]},
],
model="anthropic/claude-sonnet-4-5",
tools=[{"name": "ls", "description": "list", "input_schema": {"type": "object", "properties": {}}}],
api_key="test-api-key",
)
sent_tool_result = captured["body"]["messages"][-1]["content"][0]
assert sent_tool_result["type"] == "tool_result"
assert sent_tool_result["cache_control"] == {"type": "ephemeral"}
assert all("cache_control" not in block for block in sent_tool_result["content"])