fix(dashscope): preserve cache_control in messages #18165

This commit is contained in:
Harshit Jain 2026-01-09 20:33:52 +05:30
parent be28fcd463
commit 4dc7a14f72
No known key found for this signature in database
GPG key ID: 36C392CD4415B4CF
2 changed files with 55 additions and 29 deletions

View file

@ -2,48 +2,37 @@
Translates from OpenAI's `/v1/chat/completions` to DashScope's `/v1/chat/completions`
"""
from typing import Any, Coroutine, List, Literal, Optional, Tuple, Union, overload
from typing import TYPE_CHECKING, List, Optional, Tuple
from litellm.litellm_core_utils.prompt_templates.common_utils import (
handle_messages_with_content_list_to_str_conversion,
)
from litellm.secret_managers.main import get_secret_str
from litellm.types.llms.openai import AllMessageValues
from ...openai.chat.gpt_transformation import OpenAIGPTConfig
if TYPE_CHECKING:
from litellm.types.llms.openai import ChatCompletionToolParam
class DashScopeChatConfig(OpenAIGPTConfig):
@overload
def _transform_messages(
self, messages: List[AllMessageValues], model: str, is_async: Literal[True]
) -> Coroutine[Any, Any, List[AllMessageValues]]:
...
"""
DashScope configuration.
@overload
def _transform_messages(
DashScope supports content in list format with cache_control metadata.
See: https://github.com/BerriAI/litellm/issues/18165
"""
def remove_cache_control_flag_from_messages_and_tools(
self,
messages: List[AllMessageValues],
model: str,
is_async: Literal[False] = False,
) -> List[AllMessageValues]:
...
messages: List[AllMessageValues],
tools: Optional[List["ChatCompletionToolParam"]] = None,
) -> Tuple[List[AllMessageValues], Optional[List["ChatCompletionToolParam"]]]:
"""
DashScope supports cache_control, so we preserve it instead of removing it.
def _transform_messages(
self, messages: List[AllMessageValues], model: str, is_async: bool = False
) -> Union[List[AllMessageValues], Coroutine[Any, Any, List[AllMessageValues]]]:
Override parent behavior that strips cache_control for OpenAI compatibility.
"""
DashScope does not support content in list format.
"""
messages = handle_messages_with_content_list_to_str_conversion(messages)
if is_async:
return super()._transform_messages(
messages=messages, model=model, is_async=True
)
else:
return super()._transform_messages(
messages=messages, model=model, is_async=False
)
return messages, tools
def _get_openai_compatible_provider_info(
self, api_base: Optional[str], api_key: Optional[str]

View file

@ -111,3 +111,40 @@ class TestDashScopeConfig:
# Check for specific content in the response
assert "```python" in response.choices[0].message.content
assert "Hey from LiteLLM" in response.choices[0].message.content
def test_dashscope_preserves_cache_control(self):
"""
Test that DashScope preserves cache_control metadata in messages.
Regression test for: https://github.com/BerriAI/litellm/issues/18165
DashScope now supports cache_control, so we should NOT strip it.
"""
config = DashScopeChatConfig()
messages_with_cache = [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Long document content here...",
"cache_control": {"type": "ephemeral"},
}
],
}
]
# This should preserve cache_control (not strip it like OpenAI does)
(
transformed_messages,
tools,
) = config.remove_cache_control_flag_from_messages_and_tools(
model="qwen-turbo",
messages=messages_with_cache,
tools=None,
)
# Verify cache_control is preserved
assert transformed_messages[0]["content"][0]["cache_control"] == {
"type": "ephemeral"
}