mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
refactor(anthropic-adapter): exhaustively match delta payload lookup
Extracts the adapter stream's closed delta-type set into StreamingContentBlockDeltaType, shared by the translate layer's return type and an exhaustive match in _delta_payload_field, so adding a new delta type without handling it in the emission gate fails type-checking instead of being silently dropped.
This commit is contained in:
parent
0f9d593d29
commit
bf3a1f47dd
3 changed files with 35 additions and 10 deletions
|
|
@ -13,14 +13,18 @@ from typing import (
|
|||
List,
|
||||
Literal,
|
||||
Optional,
|
||||
get_args,
|
||||
)
|
||||
|
||||
from typing_extensions import assert_never
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm._uuid import uuid
|
||||
from litellm.types.llms.anthropic import (
|
||||
AppliedEdit,
|
||||
CompactionBlock,
|
||||
ContextManagementResponse,
|
||||
StreamingContentBlockDeltaType,
|
||||
UsageDelta,
|
||||
UsageIteration,
|
||||
)
|
||||
|
|
@ -30,6 +34,23 @@ if TYPE_CHECKING:
|
|||
from litellm.types.utils import ModelResponseStream
|
||||
|
||||
|
||||
_STREAMING_DELTA_TYPES = frozenset(get_args(StreamingContentBlockDeltaType))
|
||||
|
||||
|
||||
def _delta_payload_field(delta_type: StreamingContentBlockDeltaType) -> str:
|
||||
match delta_type:
|
||||
case "text_delta":
|
||||
return "text"
|
||||
case "input_json_delta":
|
||||
return "partial_json"
|
||||
case "thinking_delta":
|
||||
return "thinking"
|
||||
case "signature_delta":
|
||||
return "signature"
|
||||
case _:
|
||||
assert_never(delta_type)
|
||||
|
||||
|
||||
class _CombinedChunkSplitter:
|
||||
"""
|
||||
Splits a streaming chunk that carries BOTH response content and a
|
||||
|
|
@ -837,6 +858,12 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
|
|||
so the trigger chunk's delta must be re-queued or the first token of
|
||||
the new block (the first non-empty text/thinking delta, or bundled
|
||||
tool arguments) is silently dropped.
|
||||
|
||||
Delta types outside ``StreamingContentBlockDeltaType`` — the closed
|
||||
set the translate layer can produce — are treated as empty. The
|
||||
per-type payload lookup is exhaustively matched against that set in
|
||||
``_delta_payload_field``, so extending the translate layer with a new
|
||||
delta type fails type-checking here until it is handled.
|
||||
"""
|
||||
if processed_chunk.get("type") != "content_block_delta":
|
||||
return False
|
||||
|
|
@ -844,15 +871,9 @@ class AnthropicStreamWrapper(AdapterCompletionStreamWrapper):
|
|||
if not isinstance(delta, dict):
|
||||
return False
|
||||
delta_type = delta.get("type")
|
||||
if delta_type == "text_delta":
|
||||
return bool(delta.get("text"))
|
||||
if delta_type == "input_json_delta":
|
||||
return bool(delta.get("partial_json"))
|
||||
if delta_type == "thinking_delta":
|
||||
return bool(delta.get("thinking"))
|
||||
if delta_type == "signature_delta":
|
||||
return bool(delta.get("signature"))
|
||||
return False
|
||||
if delta_type not in _STREAMING_DELTA_TYPES:
|
||||
return False
|
||||
return bool(delta.get(_delta_payload_field(delta_type)))
|
||||
|
||||
def _should_start_new_content_block(self, chunk: "ModelResponseStream") -> bool:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ from litellm.types.llms.anthropic import (
|
|||
ContextManagementResponse,
|
||||
MessageBlockDelta,
|
||||
MessageDelta,
|
||||
StreamingContentBlockDeltaType,
|
||||
UsageDelta,
|
||||
UsageIteration,
|
||||
)
|
||||
|
|
@ -1423,7 +1424,7 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
def _translate_streaming_openai_chunk_to_anthropic(
|
||||
self, choices: List[Union[OpenAIStreamingChoice, StreamingChoices]]
|
||||
) -> Tuple[
|
||||
Literal["text_delta", "input_json_delta", "thinking_delta", "signature_delta"],
|
||||
StreamingContentBlockDeltaType,
|
||||
Union[
|
||||
ContentTextBlockDelta,
|
||||
ContentJsonBlockDelta,
|
||||
|
|
|
|||
|
|
@ -439,6 +439,9 @@ class ContentThinkingSignatureBlockDelta(TypedDict):
|
|||
signature: str
|
||||
|
||||
|
||||
StreamingContentBlockDeltaType = Literal["text_delta", "input_json_delta", "thinking_delta", "signature_delta"]
|
||||
|
||||
|
||||
class ContentBlockDelta(TypedDict):
|
||||
type: Literal["content_block_delta"]
|
||||
index: int
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue