1
1
from unittest import mock
2
2
3
+
3
4
try :
4
5
from unittest .mock import AsyncMock
5
6
except ImportError :
@@ -10,7 +11,7 @@ async def __call__(self, *args, **kwargs):
10
11
11
12
12
13
import pytest
13
- from anthropic import AsyncAnthropic , Anthropic , AnthropicError , AsyncStream , Stream
14
+ from anthropic import Anthropic , AnthropicError , AsyncAnthropic , AsyncStream , Stream
14
15
from anthropic .types import MessageDeltaUsage , TextDelta , Usage
15
16
from anthropic .types .content_block_delta_event import ContentBlockDeltaEvent
16
17
from anthropic .types .content_block_start_event import ContentBlockStartEvent
@@ -19,6 +20,7 @@ async def __call__(self, *args, **kwargs):
19
20
from anthropic .types .message_delta_event import MessageDeltaEvent
20
21
from anthropic .types .message_start_event import MessageStartEvent
21
22
23
+ from sentry_sdk .integrations .anthropic import _add_ai_data_to_span , _collect_ai_data
22
24
from sentry_sdk .utils import package_version
23
25
24
26
try :
@@ -42,7 +44,7 @@ async def __call__(self, *args, **kwargs):
42
44
except ImportError :
43
45
from anthropic .types .content_block import ContentBlock as TextBlock
44
46
45
- from sentry_sdk import start_transaction
47
+ from sentry_sdk import start_transaction , start_span
46
48
from sentry_sdk .consts import OP , SPANDATA
47
49
from sentry_sdk .integrations .anthropic import AnthropicIntegration
48
50
@@ -517,9 +519,8 @@ def test_streaming_create_message_with_input_json_delta(
517
519
if send_default_pii and include_prompts :
518
520
assert span ["data" ][SPANDATA .AI_INPUT_MESSAGES ] == messages
519
521
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
+ ]
523
524
else :
524
525
assert SPANDATA .AI_INPUT_MESSAGES not in span ["data" ]
525
526
assert SPANDATA .AI_RESPONSES not in span ["data" ]
@@ -654,8 +655,8 @@ async def test_streaming_create_message_with_input_json_delta_async(
654
655
if send_default_pii and include_prompts :
655
656
assert span ["data" ][SPANDATA .AI_INPUT_MESSAGES ] == messages
656
657
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
+ ]
659
660
660
661
else :
661
662
assert SPANDATA .AI_INPUT_MESSAGES not in span ["data" ]
@@ -757,3 +758,59 @@ async def test_span_origin_async(sentry_init, capture_events):
757
758
758
759
assert event ["contexts" ]["trace" ]["origin" ] == "manual"
759
760
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