11from unittest import mock
22
3+
34try :
45 from unittest .mock import AsyncMock
56except ImportError :
@@ -10,7 +11,7 @@ async def __call__(self, *args, **kwargs):
1011
1112
1213import pytest
13- from anthropic import AsyncAnthropic , Anthropic , AnthropicError , AsyncStream , Stream
14+ from anthropic import Anthropic , AnthropicError , AsyncAnthropic , AsyncStream , Stream
1415from anthropic .types import MessageDeltaUsage , TextDelta , Usage
1516from anthropic .types .content_block_delta_event import ContentBlockDeltaEvent
1617from anthropic .types .content_block_start_event import ContentBlockStartEvent
@@ -19,6 +20,7 @@ async def __call__(self, *args, **kwargs):
1920from anthropic .types .message_delta_event import MessageDeltaEvent
2021from anthropic .types .message_start_event import MessageStartEvent
2122
23+ from sentry_sdk .integrations .anthropic import _add_ai_data_to_span , _collect_ai_data
2224from sentry_sdk .utils import package_version
2325
2426try :
@@ -42,7 +44,7 @@ async def __call__(self, *args, **kwargs):
4244except ImportError :
4345 from anthropic .types .content_block import ContentBlock as TextBlock
4446
45- from sentry_sdk import start_transaction
47+ from sentry_sdk import start_transaction , start_span
4648from sentry_sdk .consts import OP , SPANDATA
4749from sentry_sdk .integrations .anthropic import AnthropicIntegration
4850
@@ -517,9 +519,8 @@ def test_streaming_create_message_with_input_json_delta(
517519 if send_default_pii and include_prompts :
518520 assert span ["data" ][SPANDATA .AI_INPUT_MESSAGES ] == messages
519521 assert span ["data" ][SPANDATA .AI_RESPONSES ] == [
520- {"text" : "" , "type" : "text" }
521- ] # we do not record InputJSONDelta because it could contain PII
522-
522+ {"text" : "{'location': 'San Francisco, CA'}" , "type" : "text" }
523+ ]
523524 else :
524525 assert SPANDATA .AI_INPUT_MESSAGES not in span ["data" ]
525526 assert SPANDATA .AI_RESPONSES not in span ["data" ]
@@ -654,8 +655,8 @@ async def test_streaming_create_message_with_input_json_delta_async(
654655 if send_default_pii and include_prompts :
655656 assert span ["data" ][SPANDATA .AI_INPUT_MESSAGES ] == messages
656657 assert span ["data" ][SPANDATA .AI_RESPONSES ] == [
657- {"text" : "" , "type" : "text" }
658- ] # we do not record InputJSONDelta because it could contain PII
658+ {"text" : "{'location': 'San Francisco, CA'} " , "type" : "text" }
659+ ]
659660
660661 else :
661662 assert SPANDATA .AI_INPUT_MESSAGES not in span ["data" ]
@@ -757,3 +758,59 @@ async def test_span_origin_async(sentry_init, capture_events):
757758
758759 assert event ["contexts" ]["trace" ]["origin" ] == "manual"
759760 assert event ["spans" ][0 ]["origin" ] == "auto.ai.anthropic"
761+
762+
763+ @pytest .mark .skipif (
764+ ANTHROPIC_VERSION < (0 , 27 ),
765+ reason = "Versions <0.27.0 do not include InputJSONDelta." ,
766+ )
767+ def test_collect_ai_data_with_input_json_delta ():
768+ event = ContentBlockDeltaEvent (
769+ delta = InputJSONDelta (partial_json = "test" , type = "input_json_delta" ),
770+ index = 0 ,
771+ type = "content_block_delta" ,
772+ )
773+
774+ input_tokens = 10
775+ output_tokens = 20
776+ content_blocks = []
777+
778+ new_input_tokens , new_output_tokens , new_content_blocks = _collect_ai_data (
779+ event , input_tokens , output_tokens , content_blocks
780+ )
781+
782+ assert new_input_tokens == input_tokens
783+ assert new_output_tokens == output_tokens
784+ assert new_content_blocks == ["test" ]
785+
786+
787+ @pytest .mark .skipif (
788+ ANTHROPIC_VERSION < (0 , 27 ),
789+ reason = "Versions <0.27.0 do not include InputJSONDelta." ,
790+ )
791+ def test_add_ai_data_to_span_with_input_json_delta (sentry_init ):
792+ sentry_init (
793+ integrations = [AnthropicIntegration (include_prompts = True )],
794+ traces_sample_rate = 1.0 ,
795+ send_default_pii = True ,
796+ )
797+
798+ with start_transaction (name = "test" ):
799+ span = start_span ()
800+ integration = AnthropicIntegration ()
801+
802+ _add_ai_data_to_span (
803+ span ,
804+ integration ,
805+ input_tokens = 10 ,
806+ output_tokens = 20 ,
807+ content_blocks = ["{'test': 'data'," , "'more': 'json'}" ],
808+ )
809+
810+ assert span ._data .get (SPANDATA .AI_RESPONSES ) == [
811+ {"type" : "text" , "text" : "{'test': 'data','more': 'json'}" }
812+ ]
813+ assert span ._data .get ("ai.streaming" ) is True
814+ assert span ._measurements .get ("ai_prompt_tokens_used" )["value" ] == 10
815+ assert span ._measurements .get ("ai_completion_tokens_used" )["value" ] == 20
816+ assert span ._measurements .get ("ai_total_tokens_used" )["value" ] == 30
0 commit comments