mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-15 04:19:08 +00:00
fix(cache_control): keep a configured point that sits beside junk entries on every chat seed path
`configured_injection_points` kept the point dicts of a mixed `cache_control_injection_points` list as a tuple, but only read a `list` back. The chat seed and the `/v1/responses` dialect stamp write the normalized value back onto the request, and on a deployment the OpenAI dialect does not stamp (an Anthropic model, Claude on Bedrock Mantle) that value is the tuple itself, so the hook then read it as no configured points and the valid point was silently dropped. The stamped OpenAI dialect and the `/v1/messages` path kept it only because they build a new list. The normalizer now reads back the tuple it wrote, so the point reaches the wire on every path; an all-dict list still passes through as the same object.
This commit is contained in:
parent
519429d256
commit
5b5898456c
2 changed files with 22 additions and 4 deletions
|
|
@ -91,10 +91,10 @@ def _validated_object_list(value: object) -> list[object] | None:
|
|||
|
||||
|
||||
def configured_injection_points(value: object) -> Sequence[CacheControlInjectionPoint]:
|
||||
if not isinstance(value, list):
|
||||
if not isinstance(value, (list, tuple)):
|
||||
return ()
|
||||
if all(isinstance(entry, dict) for entry in value):
|
||||
return cast(list[CacheControlInjectionPoint], value)
|
||||
return cast(Sequence[CacheControlInjectionPoint], value)
|
||||
return tuple(cast(CacheControlInjectionPoint, entry) for entry in value if isinstance(entry, dict))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4189,6 +4189,7 @@ class TestMalformedInjectionPointsAreIgnored:
|
|||
Every entry point now reads it as no configured points, the way ``null`` already read."""
|
||||
|
||||
SHAPES = ("system", 5, {"location": "message", "role": "system"}, ["system"], None)
|
||||
MIXED = ["system", {"location": "message", "role": "system"}, 3]
|
||||
MESSAGES = [{"role": "system", "content": "sys"}, {"role": "user", "content": "hi"}]
|
||||
|
||||
@pytest.mark.parametrize("value", SHAPES)
|
||||
|
|
@ -4196,8 +4197,25 @@ class TestMalformedInjectionPointsAreIgnored:
|
|||
assert configured_injection_points(value) == ()
|
||||
|
||||
def test_keeps_the_point_entries_of_a_mixed_list(self):
|
||||
mixed = ["system", {"location": "message", "role": "system"}, 3]
|
||||
assert configured_injection_points(mixed) == ({"location": "message", "role": "system"},)
|
||||
assert configured_injection_points(self.MIXED) == ({"location": "message", "role": "system"},)
|
||||
|
||||
def test_the_point_beside_junk_entries_survives_the_chat_seed_on_an_unstamped_deployment(self):
|
||||
params: dict = {"cache_control_injection_points": copy.deepcopy(self.MIXED)}
|
||||
AnthropicCacheControlHook.maybe_seed_default_injection_points(
|
||||
non_default_params=params,
|
||||
messages=copy.deepcopy(self.MESSAGES),
|
||||
model="claude-sonnet-4-5",
|
||||
custom_llm_provider="anthropic",
|
||||
)
|
||||
_, processed, _ = AnthropicCacheControlHook().get_chat_completion_prompt(
|
||||
model="claude-sonnet-4-5",
|
||||
messages=copy.deepcopy(self.MESSAGES),
|
||||
non_default_params=params,
|
||||
prompt_id=None,
|
||||
prompt_variables=None,
|
||||
dynamic_callback_params={},
|
||||
)
|
||||
assert processed[0] == {"role": "system", "content": "sys", "cache_control": {"type": "ephemeral"}}
|
||||
|
||||
@pytest.mark.parametrize("value", SHAPES)
|
||||
def test_chat_prompt_hook_leaves_the_request_untouched(self, value):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue