diff --git a/sentry_sdk/integrations/anthropic.py b/sentry_sdk/integrations/anthropic.py index 87e69a3113..a41005ed20 100644 --- a/sentry_sdk/integrations/anthropic.py +++ b/sentry_sdk/integrations/anthropic.py @@ -7,6 +7,7 @@ from sentry_sdk.integrations import DidNotEnable, Integration from sentry_sdk.scope import should_send_default_pii from sentry_sdk.utils import ( + _serialize_span_attribute, capture_internal_exceptions, event_from_exception, package_version, @@ -126,7 +127,7 @@ def _add_ai_data_to_span( complete_message = "".join(content_blocks) span.set_data( SPANDATA.AI_RESPONSES, - [{"type": "text", "text": complete_message}], + _serialize_span_attribute([{"type": "text", "text": complete_message}]), ) total_tokens = input_tokens + output_tokens record_token_usage(span, input_tokens, output_tokens, total_tokens) @@ -165,11 +166,16 @@ def _sentry_patched_create_common(f, *args, **kwargs): span.set_data(SPANDATA.AI_STREAMING, False) if should_send_default_pii() and integration.include_prompts: - span.set_data(SPANDATA.AI_INPUT_MESSAGES, messages) + span.set_data( + SPANDATA.AI_INPUT_MESSAGES, _serialize_span_attribute(messages) + ) if hasattr(result, "content"): if should_send_default_pii() and integration.include_prompts: - span.set_data(SPANDATA.AI_RESPONSES, _get_responses(result.content)) + span.set_data( + SPANDATA.AI_RESPONSES, + _serialize_span_attribute(_get_responses(result.content)), + ) _calculate_token_usage(result, span) span.__exit__(None, None, None) diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py index 8ce12e70f5..4a7d7ed458 100644 --- a/tests/integrations/anthropic/test_anthropic.py +++ b/tests/integrations/anthropic/test_anthropic.py @@ -19,7 +19,7 @@ async def __call__(self, *args, **kwargs): from anthropic.types.message_delta_event import MessageDeltaEvent from anthropic.types.message_start_event import MessageStartEvent -from sentry_sdk.utils import package_version +from sentry_sdk.utils import _serialize_span_attribute, package_version try: from anthropic.types import InputJSONDelta @@ -115,10 +115,12 @@ def test_nonstreaming_create_message( assert span["data"][SPANDATA.AI_MODEL_ID] == "model" if send_default_pii and include_prompts: - assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == messages - assert span["data"][SPANDATA.AI_RESPONSES] == [ - {"type": "text", "text": "Hi, I'm Claude."} - ] + assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == _serialize_span_attribute( + messages + ) + assert span["data"][SPANDATA.AI_RESPONSES] == _serialize_span_attribute( + [{"type": "text", "text": "Hi, I'm Claude."}] + ) else: assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] assert SPANDATA.AI_RESPONSES not in span["data"] @@ -183,10 +185,12 @@ async def test_nonstreaming_create_message_async( assert span["data"][SPANDATA.AI_MODEL_ID] == "model" if send_default_pii and include_prompts: - assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == messages - assert span["data"][SPANDATA.AI_RESPONSES] == [ - {"type": "text", "text": "Hi, I'm Claude."} - ] + assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == _serialize_span_attribute( + messages + ) + assert span["data"][SPANDATA.AI_RESPONSES] == _serialize_span_attribute( + [{"type": "text", "text": "Hi, I'm Claude."}] + ) else: assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] assert SPANDATA.AI_RESPONSES not in span["data"] @@ -282,10 +286,12 @@ def test_streaming_create_message( assert span["data"][SPANDATA.AI_MODEL_ID] == "model" if send_default_pii and include_prompts: - assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == messages - assert span["data"][SPANDATA.AI_RESPONSES] == [ - {"type": "text", "text": "Hi! I'm Claude!"} - ] + assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == _serialize_span_attribute( + messages + ) + assert span["data"][SPANDATA.AI_RESPONSES] == _serialize_span_attribute( + [{"type": "text", "text": "Hi! I'm Claude!"}] + ) else: assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] @@ -385,10 +391,12 @@ async def test_streaming_create_message_async( assert span["data"][SPANDATA.AI_MODEL_ID] == "model" if send_default_pii and include_prompts: - assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == messages - assert span["data"][SPANDATA.AI_RESPONSES] == [ - {"type": "text", "text": "Hi! I'm Claude!"} - ] + assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == _serialize_span_attribute( + messages + ) + assert span["data"][SPANDATA.AI_RESPONSES] == _serialize_span_attribute( + [{"type": "text", "text": "Hi! I'm Claude!"}] + ) else: assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] @@ -515,10 +523,12 @@ def test_streaming_create_message_with_input_json_delta( assert span["data"][SPANDATA.AI_MODEL_ID] == "model" if send_default_pii and include_prompts: - assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == messages - assert span["data"][SPANDATA.AI_RESPONSES] == [ - {"text": "", "type": "text"} - ] # we do not record InputJSONDelta because it could contain PII + assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == _serialize_span_attribute( + messages + ) + assert span["data"][SPANDATA.AI_RESPONSES] == _serialize_span_attribute( + [{"type": "text", "text": ""}] + ) # we do not record InputJSONDelta because it could contain PII else: assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] @@ -652,10 +662,12 @@ async def test_streaming_create_message_with_input_json_delta_async( assert span["data"][SPANDATA.AI_MODEL_ID] == "model" if send_default_pii and include_prompts: - assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == messages - assert span["data"][SPANDATA.AI_RESPONSES] == [ - {"text": "", "type": "text"} - ] # we do not record InputJSONDelta because it could contain PII + assert span["data"][SPANDATA.AI_INPUT_MESSAGES] == _serialize_span_attribute( + messages + ) + assert span["data"][SPANDATA.AI_RESPONSES] == _serialize_span_attribute( + [{"type": "text", "text": ""}] + ) # we do not record InputJSONDelta because it could contain PII else: assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] @@ -667,6 +679,7 @@ async def test_streaming_create_message_with_input_json_delta_async( assert span["data"]["ai.streaming"] is True +@pytest.mark.forked def test_exception_message_create(sentry_init, capture_events): sentry_init(integrations=[AnthropicIntegration()], traces_sample_rate=1.0) events = capture_events()