This commit is contained in:
Mahenoor Salat 2026-09-24 03:48:55 +03:00 • committed by GitHub
commit 23c820d7f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 2 deletions

View file

@ -845,7 +845,7 @@ class ModelResponseIterator:
# Track current content block type for filtering deltas
self.current_content_block_type = content_block_start["content_block"]["type"]
if content_block_start["content_block"]["type"] == "text":
text = content_block_start["content_block"]["text"]
text = content_block_start["content_block"].get("text") or ""
elif (
content_block_start["content_block"]["type"] == "tool_use"
or content_block_start["content_block"]["type"] == "server_tool_use"

View file

@ -512,7 +512,7 @@ class ToolUseBlock(TypedDict):
caller: ToolCaller | None
class TextBlock(TypedDict):
class TextBlock(TypedDict, total=False):
text: str
type: Literal["text"]

View file

@ -0,0 +1,51 @@
import pytest
from litellm.llms.anthropic.chat.handler import ModelResponseIterator
def test_chunk_parser_content_block_start_omits_text():
"""
Test that ModelResponseIterator.chunk_parser handles content_block_start
when the 'text' key is omitted by third-party Anthropic-compatible upstreams.
Fixes Issue #40689.
"""
iterator = ModelResponseIterator(streaming_response=[], sync_stream=True)
# 1. Chunk omitting "text" entirely
chunk_without_text = {
"type": "content_block_start",
"index": 0,
"content_block": {"type": "text"},
}
res = iterator.chunk_parser(chunk_without_text)
assert res is not None
assert res.choices[0].delta.content == ""
# 2. Chunk with standard official empty string text
chunk_with_empty_text = {
"type": "content_block_start",
"index": 0,
"content_block": {"type": "text", "text": ""},
}
res = iterator.chunk_parser(chunk_with_empty_text)
assert res is not None
assert res.choices[0].delta.content == ""
# 3. Chunk with text as None
chunk_with_none_text = {
"type": "content_block_start",
"index": 0,
"content_block": {"type": "text", "text": None},
}
res = iterator.chunk_parser(chunk_with_none_text)
assert res is not None
assert res.choices[0].delta.content == ""
# 4. Chunk with actual initial text
chunk_with_text = {
"type": "content_block_start",
"index": 0,
"content_block": {"type": "text", "text": "hello"},
}
res = iterator.chunk_parser(chunk_with_text)
assert res is not None
assert res.choices[0].delta.content == "hello"