From 7399b3844dfc45ab0c9ddbb116b26235ce4f7df0 Mon Sep 17 00:00:00 2001 From: Atharva-Kanherkar <142440039+Atharva-Kanherkar@users.noreply.github.com> Date: Fri, 4 Sep 2026 17:33:06 +0530 Subject: [PATCH] fix(anthropic): satisfy lint budget gates for refusal translation --- .../adapters/streaming_iterator.py | 14 +++++----- .../adapters/transformation.py | 2 +- .../responses_adapters/streaming_iterator.py | 10 +++---- .../responses_adapters/transformation.py | 28 ++++++++++--------- litellm/types/llms/anthropic.py | 2 +- 5 files changed, 29 insertions(+), 27 deletions(-) diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py b/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py index 41db4f12143..66fcad474d5 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/streaming_iterator.py @@ -11,7 +11,7 @@ from typing import ( Final, Literal, Protocol, - cast, + cast, # noqa: TID251 # rebuilt message_delta dict spans the ContentBlockDelta/MessageBlockDelta union get_args, ) @@ -306,7 +306,7 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper): # Synthesized compaction block from compact_20260112 polyfill (streaming). self.compaction_block = compaction_block self.iterations_usage = iterations_usage - self._refusal_text_parts: list[str] = [] + self._refusal_text_parts: list[str] = [] # mutable-ok: accumulates streamed refusal delta text across chunks self.sent_compaction_block: bool = False # Per-phase flags so the compaction block's start/delta/stop events # are emitted (and the public state machine is advanced) in @@ -1003,17 +1003,17 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper): ) -> ContentBlockDelta | MessageBlockDelta: if processed_chunk.get("type") != "message_delta" or not self._refusal_text_parts: return processed_chunk - delta: Final = cast(Mapping[str, object], processed_chunk["delta"]) + delta: Final = cast(Mapping[str, object], processed_chunk["delta"]) # cast-ok: keys checked before use if delta.get("stop_reason") == "max_tokens": return processed_chunk - return cast( + return cast( # cast-ok: rebuilt dict matches the message_delta TypedDict shape for this branch ContentBlockDelta | MessageBlockDelta, - { + { # mutable-ok: fresh translation payload; never mutated after construction **processed_chunk, - "delta": { + "delta": { # mutable-ok: fresh message_delta payload; never mutated after construction **delta, "stop_reason": "refusal", - "stop_details": { + "stop_details": { # mutable-ok: fresh stop_details payload; never mutated after construction "type": "refusal", "category": None, "explanation": "".join(self._refusal_text_parts), diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index 5655f59a4cc..2d950f007a5 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -1534,7 +1534,7 @@ class LiteLLMAnthropicMessagesAdapter: content=anthropic_content, stop_reason=anthropic_finish_reason, stop_details=( - { + { # mutable-ok: fresh refusal stop_details payload built per response "type": "refusal", "category": None, "explanation": refusal_text, diff --git a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py index 1b0ab5923d8..8e5ce77e48f 100644 --- a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py +++ b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py @@ -50,7 +50,7 @@ class AnthropicResponsesStreamWrapper: self._sent_message_start = False self._sent_message_stop = False self._chunk_queue: deque = deque() - self._refusal_text_parts: list[str] = [] + self._refusal_text_parts: list[str] = [] # mutable-ok: accumulates streamed refusal delta text across chunks self._sync_responses_iterator: Any = None def _make_message_start(self) -> dict[str, Any]: @@ -251,19 +251,19 @@ class AnthropicResponsesStreamWrapper: else AnthropicUsage(input_tokens=0, output_tokens=0) ) - message_delta_payload: Final = { + message_delta_payload: Final = { # mutable-ok: fresh message_delta payload built per chunk "stop_reason": stop_reason, "stop_sequence": None, **( - { - "stop_details": { + { # mutable-ok: fresh refusal stop_details payload built per chunk + "stop_details": { # mutable-ok: fresh refusal stop_details payload built per chunk "type": "refusal", "category": None, "explanation": refusal_text, } } if stop_reason == "refusal" - else {} + else {} # mutable-ok: empty spread placeholder for non-refusal stop ), } diff --git a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py index 92f3e08f24d..318065148b8 100644 --- a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py @@ -81,20 +81,20 @@ class LiteLLMAnthropicToResponsesAPIAdapter: ) if not isinstance(item, Mapping): return None - item_mapping: Final = cast(Mapping[str, object], item) + item_mapping: Final = cast(Mapping[str, object], item) # cast-ok: keys re-checked before use raw_parts: Final = item_mapping.get("content") if item_mapping.get("type") != "message" or not isinstance(raw_parts, Sequence): return None - return next( - ( - refusal - for part in cast(Sequence[object], raw_parts) - if isinstance(part, Mapping) - and cast(Mapping[str, object], part).get("type") == "refusal" - and isinstance((refusal := cast(Mapping[str, object], part).get("refusal")), str) - ), - None, - ) + for part in cast(Sequence[object], raw_parts): # cast-ok: members re-validated below + if not isinstance(part, Mapping): + continue + part_mapping = cast(Mapping[str, object], part) # cast-ok: keys re-checked before use + if part_mapping.get("type") != "refusal": + continue + refusal = part_mapping.get("refusal") + if isinstance(refusal, str): + return refusal + return None return next( (text for item in output if (text := refusal_text_from_item(item)) is not None), @@ -656,7 +656,9 @@ class LiteLLMAnthropicToResponsesAPIAdapter: content: Final[list[dict[str, object]]] = [] stop_reason: AnthropicFinishReason = "end_turn" - refusal_text: Final = self._refusal_text_from_output(cast(Iterable[object], response.output)) + refusal_text: Final = self._refusal_text_from_output( + cast(Iterable[object], response.output) # cast-ok: output items re-validated per item + ) for item in response.output: if isinstance(item, ResponseReasoningItem): @@ -746,7 +748,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter: content=content, stop_reason=stop_reason, stop_details=( - { + { # mutable-ok: fresh refusal stop_details payload built per response "type": "refusal", "category": None, "explanation": refusal_text, diff --git a/litellm/types/llms/anthropic.py b/litellm/types/llms/anthropic.py index cdfc5227e06..365d59a179b 100644 --- a/litellm/types/llms/anthropic.py +++ b/litellm/types/llms/anthropic.py @@ -528,7 +528,7 @@ class AnthropicStopDetails(TypedDict, total=False): class MessageDelta(TypedDict, total=False): stop_reason: str | None - stop_details: AnthropicStopDetails + stop_details: ReadOnly[AnthropicStopDetails] class ServerToolUsage(TypedDict, total=False):