Skip to content

Commit 0350a44

Browse files
Merge pull request #14965 from Maximgitman/issue-14962-anthropic-streaming-id
Fix Anthropic streaming IDs (#14962)
2 parents dc605b1 + f2d7c1c commit 0350a44

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

litellm/llms/anthropic/chat/handler.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
ModelResponseStream,
5252
StreamingChoices,
5353
Usage,
54+
_generate_id,
5455
)
5556

5657
from ...base import BaseLLM
@@ -490,6 +491,8 @@ def __init__(
490491
self.content_blocks: List[ContentBlockDelta] = []
491492
self.tool_index = -1
492493
self.json_mode = json_mode
494+
# Generate response ID once per stream to match OpenAI-compatible behavior
495+
self.response_id = _generate_id()
493496

494497
# Track if we're currently streaming a response_format tool
495498
self.is_response_format_tool: bool = False
@@ -765,6 +768,7 @@ def chunk_parser(self, chunk: dict) -> ModelResponseStream:
765768
)
766769
],
767770
usage=usage,
771+
id=self.response_id,
768772
)
769773

770774
return returned_chunk
@@ -936,4 +940,4 @@ def convert_str_chunk_to_generic_chunk(self, chunk: str) -> ModelResponseStream:
936940
data_json = json.loads(str_line[5:])
937941
return self.chunk_parser(chunk=data_json)
938942
else:
939-
return ModelResponseStream()
943+
return ModelResponseStream(id=self.response_id)

tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,24 @@ def test_multiple_tools_streaming_has_index_zero():
439439
assert (
440440
parsed.choices[0].index == 0
441441
), f"Expected index=0, got {parsed.choices[0].index}"
442+
443+
444+
def test_streaming_chunks_have_stable_ids():
445+
iterator = ModelResponseIterator(
446+
streaming_response=MagicMock(), sync_stream=False, json_mode=False
447+
)
448+
first_chunk = {
449+
"type": "content_block_delta",
450+
"index": 0,
451+
"delta": {"type": "text_delta", "text": "Hello"},
452+
}
453+
second_chunk = {
454+
"type": "content_block_delta",
455+
"index": 0,
456+
"delta": {"type": "text_delta", "text": " world"},
457+
}
458+
459+
response_one = iterator.chunk_parser(chunk=first_chunk)
460+
response_two = iterator.chunk_parser(chunk=second_chunk)
461+
462+
assert response_one.id == response_two.id == iterator.response_id

0 commit comments

Comments
 (0)