Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ddtrace/contrib/internal/anthropic/_streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ def _on_content_block_delta_chunk(chunk, message):

def _on_content_block_stop_chunk(chunk, message):
# this is the start to a message.content block (possibly 1 of several content blocks)
# Anthropic beta streaming can emit content_block_stop without a corresponding
# content_block_start (e.g. empty tool blocks / vendor edge cases). Guard to
# avoid IndexError which breaks span construction.
if not message.get("content"):
return message

content_type = _get_attr(message["content"][-1], "type", "")
if content_type == "tool_use":
input_json = _get_attr(message["content"][-1], "input", "{}")
Expand Down
7 changes: 7 additions & 0 deletions tests/contrib/anthropic/test_anthropic_llmobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@
],
)
class TestLLMObsAnthropic:
def test_content_block_stop_without_content_does_not_crash(self):
"""Regression test for beta streaming: content_block_stop can arrive without any content blocks."""
from ddtrace.contrib.internal.anthropic._streaming import _on_content_block_stop_chunk

message = {"content": []}
assert _on_content_block_stop_chunk(chunk=None, message=message) == message

@patch("anthropic._base_client.SyncAPIClient.post")
def test_completion_proxy(
self,
Expand Down