fix(anthropic): satisfy lint budget gates for refusal translation

This commit is contained in:
Atharva-Kanherkar 2026-09-04 17:33:06 +05:30
parent 0b34abe8fe
commit 7399b3844d
5 changed files with 29 additions and 27 deletions

View file

@ -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),

View file

@ -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,

View file

@ -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
),
}

View file

@ -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,

View file

@ -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):