mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-16 23:41:43 +00:00
style(anthropic): trim excess thinking-block predicate/test commentary
This commit is contained in:
parent
01683f2bd9
commit
dfba491fa4
2 changed files with 13 additions and 54 deletions
|
|
@ -2302,20 +2302,14 @@ def sanitize_messages_for_tool_calling(
|
|||
def _is_unsignable_thinking_block(block: object) -> bool:
|
||||
"""A thinking block that Anthropic cannot accept on input.
|
||||
|
||||
Anthropic verifies the thinking signature cryptographically, so a block whose
|
||||
signature is null, empty, or missing (e.g. from an open-source reasoning model)
|
||||
is rejected with a 400 and must be dropped rather than blanked or repaired, and
|
||||
so is a block whose signature or data carries another provider's encrypted
|
||||
reasoning. A `redacted_thinking` block Anthropic minted is always kept.
|
||||
|
||||
Anthropic also rejects a `thinking` block whose `thinking` text is empty or
|
||||
whitespace-only ("each thinking block must contain thinking"), regardless of
|
||||
signature. This shape reaches us when a caller replays a `thinking_blocks`
|
||||
history item that originated from a non-Anthropic reasoning provider (e.g. an
|
||||
OpenAI Responses-API turn with no summary text) through this Anthropic-shaped
|
||||
request path (`/v1/chat/completions` -> anthropic/vertex_ai's claude models),
|
||||
which is the same failure the Anthropic Responses-bridge adapter guards
|
||||
against (see PR #36033) for its own separate content-block path.
|
||||
Anthropic verifies the signature cryptographically, so a block with a null,
|
||||
empty, or missing signature (e.g. from an open-source reasoning model) is
|
||||
rejected with a 400, and so is a block whose signature or data carries
|
||||
another provider's encrypted reasoning. It also rejects a `thinking` block
|
||||
whose text is empty or whitespace-only ("each thinking block must contain
|
||||
thinking"), regardless of signature, e.g. when a `thinking_blocks` history
|
||||
item from a non-Anthropic reasoning provider is replayed through this path.
|
||||
`redacted_thinking` blocks carry no signature and are always kept.
|
||||
"""
|
||||
if is_encrypted_reasoning_block(block):
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -3722,14 +3722,7 @@ def test_convert_to_anthropic_tool_invoke_keeps_paired_server_tool_use():
|
|||
server_result,
|
||||
]
|
||||
def test_anthropic_messages_pt_drops_empty_but_signed_thinking_block():
|
||||
"""
|
||||
Anthropic rejects a `thinking` block whose `thinking` text is empty, even
|
||||
when it carries a valid-looking signature, with:
|
||||
400 messages.N.content.M.thinking: each thinking block must contain thinking
|
||||
This shape is reachable via cross-provider replay of a `thinking_blocks`
|
||||
history item (see PR #36033), so `_is_unsignable_thinking_block()` must
|
||||
also check the thinking text, not just the signature.
|
||||
"""
|
||||
"""An empty-but-signed thinking block must still be dropped."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
anthropic_messages_pt,
|
||||
)
|
||||
|
|
@ -3762,10 +3755,7 @@ def test_anthropic_messages_pt_drops_empty_but_signed_thinking_block():
|
|||
|
||||
|
||||
def test_anthropic_messages_pt_keeps_non_empty_signed_thinking_block():
|
||||
"""
|
||||
Regression: a real, non-empty, signed thinking block must still pass
|
||||
through unchanged.
|
||||
"""
|
||||
"""Regression: a non-empty, signed thinking block passes through unchanged."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
anthropic_messages_pt,
|
||||
)
|
||||
|
|
@ -3800,11 +3790,7 @@ def test_anthropic_messages_pt_keeps_non_empty_signed_thinking_block():
|
|||
|
||||
|
||||
def test_anthropic_messages_pt_keeps_redacted_thinking_block():
|
||||
"""
|
||||
Regression: `redacted_thinking` blocks carry no signature and no plaintext
|
||||
`thinking` field by design, and must always be kept regardless of the new
|
||||
emptiness check (which only applies to `type == "thinking"` blocks).
|
||||
"""
|
||||
"""Regression: redacted_thinking blocks are unaffected by the emptiness check."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
anthropic_messages_pt,
|
||||
)
|
||||
|
|
@ -3836,11 +3822,7 @@ def test_anthropic_messages_pt_keeps_redacted_thinking_block():
|
|||
|
||||
|
||||
def test_anthropic_messages_pt_drops_unsigned_thinking_block():
|
||||
"""
|
||||
Regression (pre-existing behaviour): a thinking block with no signature
|
||||
(or an empty/null one) must still be dropped, independent of whether the
|
||||
thinking text is populated.
|
||||
"""
|
||||
"""Regression: an unsigned thinking block is still dropped, regardless of text."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
anthropic_messages_pt,
|
||||
)
|
||||
|
|
@ -3873,24 +3855,7 @@ def test_anthropic_messages_pt_drops_unsigned_thinking_block():
|
|||
|
||||
|
||||
def test_is_unsignable_thinking_block_treats_whitespace_only_as_empty():
|
||||
"""
|
||||
Edge case: a `thinking` field that is present but whitespace-only (e.g.
|
||||
a single trailing newline forwarded from another provider's empty
|
||||
reasoning summary) is functionally empty and Anthropic's API will still
|
||||
reject it with "each thinking block must contain thinking". We treat it
|
||||
the same as a fully empty string and drop the block.
|
||||
|
||||
Note the sibling check ~30 lines below this function's definition
|
||||
(the "don't pass empty text blocks" comment) uses a bare
|
||||
`len(thinking_block) > 0`, which by itself would treat whitespace-only
|
||||
text as non-empty. That sibling check is always combined with
|
||||
`not _is_unsignable_thinking_block(m)` in an `and`, so this function's
|
||||
stricter whitespace-aware check is still the one that decides whether a
|
||||
whitespace-only block survives — the two checks don't disagree in
|
||||
practice, but this function is intentionally the stricter of the two
|
||||
since it is also called standalone (via `_drop_unsignable_thinking_blocks`)
|
||||
without that extra `len(...) > 0` guard.
|
||||
"""
|
||||
"""Whitespace-only `thinking` text is treated as empty and dropped."""
|
||||
from litellm.litellm_core_utils.prompt_templates.factory import (
|
||||
_is_unsignable_thinking_block,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue