From cabcc738b46f09afe863ea672a317926f4195703 Mon Sep 17 00:00:00 2001 From: Tan Nguyen Date: Thu, 1 Oct 2026 21:17:54 +0700 Subject: [PATCH] fix(anthropic): return the resolved indices as a tuple and type the narrowed message dict The resolver built three lists that nothing mutates, and the message a type guard narrowed to dict carried unknown key and value types into the block walk-back. Both sit under the repo's type-discipline and basedpyright budgets. --- .../integrations/anthropic_cache_control_hook.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/litellm/integrations/anthropic_cache_control_hook.py b/litellm/integrations/anthropic_cache_control_hook.py index f511b453f08..7ddcd796072 100644 --- a/litellm/integrations/anthropic_cache_control_hook.py +++ b/litellm/integrations/anthropic_cache_control_hook.py @@ -252,8 +252,9 @@ def _message_accepts_cache_control(message: object) -> bool: """Whether a marker written on this message reaches the provider.""" if not isinstance(message, dict): return False - on_a_tool_message: Final = message.get("role") == "tool" - content: Final = message.get("content") + fields: Final = cast(dict[str, object], message) # cast-ok: a runtime dict whose value types are not known here + on_a_tool_message: Final = fields.get("role") == "tool" + content: Final = fields.get("content") if isinstance(content, str): return content != "" or on_a_tool_message if isinstance(content, list): @@ -563,7 +564,7 @@ class AnthropicCacheControlHook(CustomPromptManagement): @staticmethod def _resolve_target_indices( point: CacheControlMessageInjectionPoint, messages: list[AllMessageValues] - ) -> list[int]: + ) -> tuple[int, ...]: """Resolve which message indices an injection point targets.""" _targetted_index: Final[int | str | None] = point.get("index", None) targetted_index: int | None = None @@ -590,7 +591,7 @@ class AnthropicCacheControlHook(CustomPromptManagement): # Case 1: Target by role alone if targetted_index is None: - return [] if targetted_role is None else [index for index in candidates if index in free] + return () if targetted_role is None else tuple(index for index in candidates if index in free) # Case 2: Target by index, counted within the role the point named position: Final = targetted_index + len(candidates) if targetted_index < 0 else targetted_index @@ -601,10 +602,10 @@ class AnthropicCacheControlHook(CustomPromptManagement): len(candidates), position, ) - return [] + return () landing: Final = next((candidates[step] for step in range(position, -1, -1) if candidates[step] in free), None) - return [] if landing is None else [landing] + return () if landing is None else (landing,) @staticmethod def _count_cache_control_blocks(message: object) -> int: