mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
fix: clear test-quality (TQ008) and basedpyright gate breaches
TQ008: the 16 new handler-level tests patch litellm. internals (litellm.acompletion, the handler adapter, _prepare_* seams). Each patch line carries an explainable test-quality-ok: reason - the unit under test IS the handler's thinking_disabled translation wiring, not the transport. basedpyright (delta vs base): - reportPrivateUsage: the shared-classifier delegation added a protected cross-class call. _chunk_has_substantial_content now derives the decision inline (same per-choice conditions, same getattr guards, same .strip()/truthy semantics as the classifier, documented). - reportOptionalSubscript/MemberAccess: the content_block tool branch relies on the classifier for tool_call presence; restored explicit narrowing (assert + local first_tool_call), behaviour-neutral. - dropped Choices from the emitter/content_block Sequence unions: the bare-Choices member re-opened Optional on delta.tool_calls[0].function (the 3 # type: ignore it used to sit next to were dead code anyway). litellm.types.utils.StreamingChoices imported at top level.
This commit is contained in:
parent
54c7405083
commit
63323a1dfd
3 changed files with 64 additions and 27 deletions
|
|
@ -31,7 +31,7 @@ from litellm.types.llms.anthropic import (
|
|||
UsageDelta,
|
||||
UsageIteration,
|
||||
)
|
||||
from litellm.types.utils import AdapterCompletionStreamWrapper, Delta
|
||||
from litellm.types.utils import AdapterCompletionStreamWrapper, Delta, StreamingChoices
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObject
|
||||
|
|
@ -1164,16 +1164,45 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
|
|||
pre-existing tests (test_empty_chunk_is_not_substantial,
|
||||
test_reasoning_chunk_is_substantial) call it unbound as
|
||||
AnthropicStreamWrapper._chunk_has_substantial_content(chunk) — converting
|
||||
to an instance method would break those calls."""
|
||||
from .transformation import LiteLLMAnthropicMessagesAdapter
|
||||
to an instance method would break those calls.
|
||||
|
||||
return (
|
||||
LiteLLMAnthropicMessagesAdapter._classify_streaming_chunk(
|
||||
choices=chunk.choices,
|
||||
thinking_disabled=thinking_disabled,
|
||||
The two sites' conditions are kept identical in code so they cannot
|
||||
drift into two different notions of substantiality (the CTG-85 failure
|
||||
mode). Rules mirrored from the classifier, per choice, with the same
|
||||
getattr-with-default guards (Delta deletes reasoning_content /
|
||||
thinking_blocks entirely when unset):
|
||||
|
||||
- a reasoning-only chunk is not substantial when thinking is disabled;
|
||||
- a structured thinking / redacted block is always substantial (even
|
||||
with an empty payload) when thinking is enabled;
|
||||
- a flat reasoning_content string is substantial only when it carries
|
||||
non-whitespace, when thinking is enabled;
|
||||
- a tool call with a function, and a truthy (NOT .strip()-based) text
|
||||
content, are substantial regardless of thinking state."""
|
||||
for choice in chunk.choices:
|
||||
reasoning_text = ""
|
||||
has_structured_thinking_block = False
|
||||
if isinstance(choice, StreamingChoices):
|
||||
thinking_blocks = getattr(choice.delta, "thinking_blocks", None) or []
|
||||
if len(thinking_blocks) > 0:
|
||||
first_block = thinking_blocks[0]
|
||||
if first_block.get("type") in ("thinking", "redacted_thinking"):
|
||||
has_structured_thinking_block = True
|
||||
reasoning_text = str(first_block.get("thinking") or "")
|
||||
if not has_structured_thinking_block:
|
||||
reasoning_text = str(getattr(choice.delta, "reasoning_content", "") or "")
|
||||
has_substantial_reasoning = bool(reasoning_text.strip()) or has_structured_thinking_block
|
||||
has_tool_calls = (
|
||||
choice.delta.tool_calls is not None
|
||||
and len(choice.delta.tool_calls) > 0
|
||||
and choice.delta.tool_calls[0].function is not None
|
||||
)
|
||||
!= "skip"
|
||||
)
|
||||
text_content = str(choice.delta.content or "")
|
||||
if has_tool_calls or bool(text_content):
|
||||
return True
|
||||
if not thinking_disabled and has_substantial_reasoning:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _is_blank_delta(chunk: "ModelResponseStream") -> bool:
|
||||
|
|
|
|||
|
|
@ -1667,7 +1667,7 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
|
||||
def _translate_streaming_openai_chunk_to_anthropic_content_block(
|
||||
self,
|
||||
choices: Sequence["OpenAIStreamingChoice | StreamingChoices | Choices"],
|
||||
choices: Sequence["OpenAIStreamingChoice | StreamingChoices"],
|
||||
thinking_disabled: bool = False,
|
||||
) -> tuple[
|
||||
Literal["text", "tool_use", "thinking", "redacted_thinking"],
|
||||
|
|
@ -1709,8 +1709,16 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
return "redacted_thinking", cast("ContentBlockContentBlockDict", redacted_block)
|
||||
|
||||
if block_type == "tool_use":
|
||||
raw_id = choice.delta.tool_calls[0].id or str(uuid.uuid4())
|
||||
tool_name = choice.delta.tool_calls[0].function.name or ""
|
||||
# Explicit narrowing (base pattern): the classifier only emits
|
||||
# "tool_use" when the first tool call carries a function, so
|
||||
# these asserts hold and keep the member accesses below
|
||||
# optional-free without changing behaviour.
|
||||
tool_calls = choice.delta.tool_calls
|
||||
assert tool_calls is not None and len(tool_calls) > 0
|
||||
first_tool_call = tool_calls[0]
|
||||
assert first_tool_call.function is not None
|
||||
raw_id = first_tool_call.id or str(uuid.uuid4())
|
||||
tool_name = first_tool_call.function.name or ""
|
||||
thought_sig: str | None = None
|
||||
if THOUGHT_SIGNATURE_SEPARATOR in raw_id:
|
||||
parts = raw_id.split(THOUGHT_SIGNATURE_SEPARATOR, 1)
|
||||
|
|
@ -1732,7 +1740,7 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
|
||||
def _translate_streaming_openai_chunk_to_anthropic(
|
||||
self,
|
||||
choices: Sequence["OpenAIStreamingChoice | StreamingChoices | Choices"],
|
||||
choices: Sequence["OpenAIStreamingChoice | StreamingChoices"],
|
||||
thinking_disabled: bool = False,
|
||||
) -> tuple[
|
||||
StreamingContentBlockDeltaType,
|
||||
|
|
|
|||
|
|
@ -43,17 +43,17 @@ async def test_async_handler_streaming_threads_thinking_disabled(thinking_param,
|
|||
"""Async handler, stream=True: ``thinking_disabled`` reaches the streaming
|
||||
adapter call."""
|
||||
with (
|
||||
patch(
|
||||
patch( # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
"litellm.llms.anthropic.experimental_pass_through.adapters.handler._prepare_context_managed_request",
|
||||
return_value=None,
|
||||
),
|
||||
patch.object(
|
||||
patch.object( # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
LiteLLMMessagesToCompletionTransformationHandler,
|
||||
"_prepare_completion_kwargs",
|
||||
return_value=({}, {}),
|
||||
),
|
||||
patch("litellm.acompletion", return_value=MagicMock()),
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter,
|
||||
patch("litellm.acompletion", return_value=MagicMock()), # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter, # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
):
|
||||
mock_adapter.translate_completion_output_params_streaming.return_value = iter([])
|
||||
await LiteLLMMessagesToCompletionTransformationHandler.async_anthropic_messages_handler(
|
||||
|
|
@ -82,17 +82,17 @@ async def test_async_handler_non_streaming_threads_thinking_disabled(thinking_pa
|
|||
"""Async handler, stream=False: ``thinking_disabled`` reaches the
|
||||
non-streaming adapter call."""
|
||||
with (
|
||||
patch(
|
||||
patch( # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
"litellm.llms.anthropic.experimental_pass_through.adapters.handler._prepare_context_managed_request",
|
||||
return_value=None,
|
||||
),
|
||||
patch.object(
|
||||
patch.object( # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
LiteLLMMessagesToCompletionTransformationHandler,
|
||||
"_prepare_completion_kwargs",
|
||||
return_value=({}, {}),
|
||||
),
|
||||
patch("litellm.acompletion", return_value=MagicMock()),
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter,
|
||||
patch("litellm.acompletion", return_value=MagicMock()), # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter, # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
):
|
||||
mock_adapter.translate_completion_output_params.return_value = MagicMock()
|
||||
await LiteLLMMessagesToCompletionTransformationHandler.async_anthropic_messages_handler(
|
||||
|
|
@ -125,13 +125,13 @@ def test_sync_handler_streaming_threads_thinking_disabled(thinking_param, expect
|
|||
blocks) so ``run_async_function`` is never invoked.
|
||||
"""
|
||||
with (
|
||||
patch.object(
|
||||
patch.object( # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
LiteLLMMessagesToCompletionTransformationHandler,
|
||||
"_prepare_completion_kwargs",
|
||||
return_value=({}, {}),
|
||||
),
|
||||
patch("litellm.completion", return_value=MagicMock()),
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter,
|
||||
patch("litellm.completion", return_value=MagicMock()), # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter, # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
):
|
||||
mock_adapter.translate_completion_output_params_streaming.return_value = iter([])
|
||||
LiteLLMMessagesToCompletionTransformationHandler.anthropic_messages_handler(
|
||||
|
|
@ -164,13 +164,13 @@ def test_sync_handler_non_streaming_threads_thinking_disabled(thinking_param, ex
|
|||
blocks) so ``run_async_function`` is never invoked.
|
||||
"""
|
||||
with (
|
||||
patch.object(
|
||||
patch.object( # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
LiteLLMMessagesToCompletionTransformationHandler,
|
||||
"_prepare_completion_kwargs",
|
||||
return_value=({}, {}),
|
||||
),
|
||||
patch("litellm.completion", return_value=MagicMock()),
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter,
|
||||
patch("litellm.completion", return_value=MagicMock()), # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
patch("litellm.llms.anthropic.experimental_pass_through.adapters.handler.ANTHROPIC_ADAPTER") as mock_adapter, # test-quality-ok: handler unit test - fakes completion dispatch + adapter seams; unit under test is the thinking_disabled translation wiring, not the transport
|
||||
):
|
||||
mock_adapter.translate_completion_output_params.return_value = MagicMock()
|
||||
LiteLLMMessagesToCompletionTransformationHandler.anthropic_messages_handler(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue