Skip to content
Draft
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 sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,12 @@ class SPANDATA:
Example: 2048
"""

GEN_AI_SYSTEM_INSTRUCTIONS = "gen_ai.system_instructions"
"""
The system instructions passed to the model.
Example: [{"type": "text", "text": "You are a helpful assistant."},{"type": "text", "text": "Be concise and clear."}]
"""

GEN_AI_REQUEST_MESSAGES = "gen_ai.request.messages"
"""
The messages passed to the model. The "content" can be a string or an array of objects.
Expand Down
25 changes: 4 additions & 21 deletions sentry_sdk/integrations/anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,29 +192,12 @@ def _set_input_data(
and should_send_default_pii()
and integration.include_prompts
):
normalized_messages = []
if system_prompt:
system_prompt_content: "Optional[Union[str, List[dict[str, Any]]]]" = None
if isinstance(system_prompt, str):
system_prompt_content = system_prompt
elif isinstance(system_prompt, Iterable):
system_prompt_content = []
for item in system_prompt:
if (
isinstance(item, dict)
and item.get("type") == "text"
and item.get("text")
):
system_prompt_content.append(item.copy())

if system_prompt_content:
normalized_messages.append(
{
"role": GEN_AI_ALLOWED_MESSAGE_ROLES.SYSTEM,
"content": system_prompt_content,
}
)
set_data_normalized(
span, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, system_prompt, unpack=False
)

normalized_messages = []
for message in messages:
if (
message.get("role") == GEN_AI_ALLOWED_MESSAGE_ROLES.USER
Expand Down
86 changes: 46 additions & 40 deletions tests/integrations/anthropic/test_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1074,17 +1074,18 @@ def test_nonstreaming_create_message_with_system_prompt(
assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model"

if send_default_pii and include_prompts:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"]
system_instructions = span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]
assert system_instructions == "You are a helpful assistant."

assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"]
stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES])
assert len(stored_messages) == 2
# System message should be first
assert stored_messages[0]["role"] == "system"
assert stored_messages[0]["content"] == "You are a helpful assistant."
# User message should be second
assert stored_messages[1]["role"] == "user"
assert stored_messages[1]["content"] == "Hello, Claude"
assert len(stored_messages) == 1
assert stored_messages[0]["role"] == "user"
assert stored_messages[0]["content"] == "Hello, Claude"
assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude."
else:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"]
assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"]
assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"]

Expand Down Expand Up @@ -1153,17 +1154,18 @@ async def test_nonstreaming_create_message_with_system_prompt_async(
assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model"

if send_default_pii and include_prompts:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"]
system_instructions = span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]
assert system_instructions == "You are a helpful assistant."

assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"]
stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES])
assert len(stored_messages) == 2
# System message should be first
assert stored_messages[0]["role"] == "system"
assert stored_messages[0]["content"] == "You are a helpful assistant."
# User message should be second
assert stored_messages[1]["role"] == "user"
assert stored_messages[1]["content"] == "Hello, Claude"
assert len(stored_messages) == 1
assert stored_messages[0]["role"] == "user"
assert stored_messages[0]["content"] == "Hello, Claude"
assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude."
else:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"]
assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"]
assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"]

Expand Down Expand Up @@ -1264,18 +1266,19 @@ def test_streaming_create_message_with_system_prompt(
assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model"

if send_default_pii and include_prompts:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"]
system_instructions = span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]
assert system_instructions == "You are a helpful assistant."

assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"]
stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES])
assert len(stored_messages) == 2
# System message should be first
assert stored_messages[0]["role"] == "system"
assert stored_messages[0]["content"] == "You are a helpful assistant."
# User message should be second
assert stored_messages[1]["role"] == "user"
assert stored_messages[1]["content"] == "Hello, Claude"
assert len(stored_messages) == 1
assert stored_messages[0]["role"] == "user"
assert stored_messages[0]["content"] == "Hello, Claude"
assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!"

else:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"]
assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"]
assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"]

Expand Down Expand Up @@ -1379,18 +1382,19 @@ async def test_streaming_create_message_with_system_prompt_async(
assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model"

if send_default_pii and include_prompts:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"]
system_instructions = span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]
assert system_instructions == "You are a helpful assistant."

assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"]
stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES])
assert len(stored_messages) == 2
# System message should be first
assert stored_messages[0]["role"] == "system"
assert stored_messages[0]["content"] == "You are a helpful assistant."
# User message should be second
assert stored_messages[1]["role"] == "user"
assert stored_messages[1]["content"] == "Hello, Claude"
assert len(stored_messages) == 1
assert stored_messages[0]["role"] == "user"
assert stored_messages[0]["content"] == "Hello, Claude"
assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!"

else:
assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"]
assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"]
assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"]

Expand Down Expand Up @@ -1437,21 +1441,23 @@ def test_system_prompt_with_complex_structure(sentry_init, capture_events):
(span,) = event["spans"]

assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat"

assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"]
system_instructions = json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS])

# System content should be a list of text blocks
assert isinstance(system_instructions, list)
assert system_instructions[0]["type"] == "text"
assert system_instructions[0]["text"] == "You are a helpful assistant."
assert system_instructions[1]["type"] == "text"
assert system_instructions[1]["text"] == "Be concise and clear."

assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"]
stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES])

# Should have system message first, then user message
assert len(stored_messages) == 2
assert stored_messages[0]["role"] == "system"
# System content should be a list of text blocks
assert isinstance(stored_messages[0]["content"], list)
assert len(stored_messages[0]["content"]) == 2
assert stored_messages[0]["content"][0]["type"] == "text"
assert stored_messages[0]["content"][0]["text"] == "You are a helpful assistant."
assert stored_messages[0]["content"][1]["type"] == "text"
assert stored_messages[0]["content"][1]["text"] == "Be concise and clear."
assert stored_messages[1]["role"] == "user"
assert stored_messages[1]["content"] == "Hello"
assert len(stored_messages) == 1
assert stored_messages[0]["role"] == "user"
assert stored_messages[0]["content"] == "Hello"


# Tests for transform_content_part (shared) and _transform_anthropic_content_block helper functions
Expand Down
Loading