From f2d7c1c14da1372880043b5d8b9f733702acab36 Mon Sep 17 00:00:00 2001 From: Maximgitman Date: Fri, 26 Sep 2025 18:31:10 -0400 Subject: [PATCH] Fix Anthropic streaming IDs --- litellm/llms/anthropic/chat/handler.py | 6 +++++- .../chat/test_anthropic_chat_handler.py | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/litellm/llms/anthropic/chat/handler.py b/litellm/llms/anthropic/chat/handler.py index 5618c50923e..b7b39f10395 100644 --- a/litellm/llms/anthropic/chat/handler.py +++ b/litellm/llms/anthropic/chat/handler.py @@ -51,6 +51,7 @@ from litellm.types.utils import ( ModelResponseStream, StreamingChoices, Usage, + _generate_id, ) from ...base import BaseLLM @@ -490,6 +491,8 @@ class ModelResponseIterator: self.content_blocks: List[ContentBlockDelta] = [] self.tool_index = -1 self.json_mode = json_mode + # Generate response ID once per stream to match OpenAI-compatible behavior + self.response_id = _generate_id() # Track if we're currently streaming a response_format tool self.is_response_format_tool: bool = False @@ -765,6 +768,7 @@ class ModelResponseIterator: ) ], usage=usage, + id=self.response_id, ) return returned_chunk @@ -936,4 +940,4 @@ class ModelResponseIterator: data_json = json.loads(str_line[5:]) return self.chunk_parser(chunk=data_json) else: - return ModelResponseStream() + return ModelResponseStream(id=self.response_id) diff --git a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py index 4ba823749cd..588abfee3f4 100644 --- a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py +++ b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py @@ -439,3 +439,24 @@ def test_multiple_tools_streaming_has_index_zero(): assert ( parsed.choices[0].index == 0 ), f"Expected index=0, got {parsed.choices[0].index}" + + +def test_streaming_chunks_have_stable_ids(): + iterator = ModelResponseIterator( + streaming_response=MagicMock(), sync_stream=False, json_mode=False + ) + first_chunk = { + "type": "content_block_delta", + "index": 0, + "delta": {"type": "text_delta", "text": "Hello"}, + } + second_chunk = { + "type": "content_block_delta", + "index": 0, + "delta": {"type": "text_delta", "text": " world"}, + } + + response_one = iterator.chunk_parser(chunk=first_chunk) + response_two = iterator.chunk_parser(chunk=second_chunk) + + assert response_one.id == response_two.id == iterator.response_id