From 1bf3ffe429c28d61db996269aef3ef01a003c077 Mon Sep 17 00:00:00 2001 From: alabenayed Date: Thu, 6 Aug 2026 15:30:01 +0300 Subject: [PATCH 1/2] fix(anthropic): order messages after system/tools in request body AnthropicConfig.transform_request built the request dict with messages before optional_params, so system and tools (spread in via **optional_params) landed after messages in the serialized JSON body. On the Vertex AI global endpoint, Anthropic's prompt cache keys off the raw request bytes rather than parsed content, so a stable system/tools prefix only hits the cache on repeat turns when messages, the part that changes every turn, comes last. With messages first, every turn after the first missed the cache and re-wrote the full prefix. Fixes #35908 --- litellm/llms/anthropic/chat/transformation.py | 7 ++++- .../test_anthropic_chat_transformation.py | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index 7bbdb9a43fd..022fce01ded 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -1935,10 +1935,15 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): output_key="top_k", ) + # ``messages`` must be the last key in the serialized request body: Anthropic's + # prompt cache (observed on the Vertex AI global endpoint) keys off the raw + # request bytes, and a stable ``system``/``tools`` prefix only hits the cache + # on repeat turns when ``messages`` (the part that changes every turn) is + # ordered after them, not before. data: Final = { "model": model, - "messages": anthropic_messages, **optional_params, + "messages": anthropic_messages, } self._apply_output_config(data=data, model=model, optional_params=optional_params) diff --git a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py index 231d3b48754..17c28245e5b 100644 --- a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py +++ b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py @@ -916,6 +916,35 @@ def test_anthropic_chat_transform_request_includes_context_management(): assert result["context_management"] == _sample_context_management_payload() +def test_anthropic_chat_transform_request_orders_messages_last(): + config = AnthropicConfig() + result = config.transform_request( + model="claude-sonnet-4-20250514", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello"}, + ], + optional_params={ + "tools": [ + { + "name": "get_weather", + "input_schema": {"type": "object", "properties": {}}, + } + ], + "max_tokens": 256, + }, + litellm_params={}, + headers={}, + ) + + keys = list(result.keys()) + assert "system" in keys + assert "tools" in keys + assert keys.index("messages") > keys.index("system") + assert keys.index("messages") > keys.index("tools") + assert keys[-1] == "messages" + + def test_anthropic_structured_output_beta_header(): from litellm.types.utils import CallTypes from litellm.utils import return_raw_request From a8482b1a06d2ad8db60bf367f5aafcf2896cff39 Mon Sep 17 00:00:00 2001 From: alabenayed Date: Thu, 6 Aug 2026 15:43:53 +0300 Subject: [PATCH 2/2] fix(anthropic): remove explanatory comment per repo convention Address Greptile review feedback: drop the new comment, since this repo's guidance is not to add comments unless explicitly requested. --- litellm/llms/anthropic/chat/transformation.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index 022fce01ded..68736023291 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -1935,11 +1935,6 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): output_key="top_k", ) - # ``messages`` must be the last key in the serialized request body: Anthropic's - # prompt cache (observed on the Vertex AI global endpoint) keys off the raw - # request bytes, and a stable ``system``/``tools`` prefix only hits the cache - # on repeat turns when ``messages`` (the part that changes every turn) is - # ordered after them, not before. data: Final = { "model": model, **optional_params,