From cca4b76106ba250c5302ff8c648961736141be26 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 11 Sep 2026 13:25:36 +0200 Subject: [PATCH 1/4] chore: Replace deprecated gen_ai.usage.input_tokens.cached with gen_ai.usage.cache_read.input_tokens --- sentry_sdk/ai/monitoring.py | 2 +- .../integrations/google_genai/streaming.py | 2 +- sentry_sdk/integrations/google_genai/utils.py | 2 +- .../integrations/openai_agents/utils.py | 2 +- .../integrations/pydantic_ai/spans/utils.py | 4 +++- .../integrations/anthropic/test_anthropic.py | 14 ++++++------- .../google_genai/test_google_genai.py | 4 ++-- tests/integrations/openai/test_openai.py | 8 ++++---- .../openai_agents/test_openai_agents.py | 20 +++++++++++++++---- .../pydantic_ai/test_pydantic_ai.py | 2 +- 10 files changed, 37 insertions(+), 23 deletions(-) diff --git a/sentry_sdk/ai/monitoring.py b/sentry_sdk/ai/monitoring.py index 5f096cc8cc..9657d82ad4 100644 --- a/sentry_sdk/ai/monitoring.py +++ b/sentry_sdk/ai/monitoring.py @@ -26,7 +26,7 @@ def record_token_usage( if input_tokens_cached is not None: _set_span_data_attribute( span, - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, input_tokens_cached, ) diff --git a/sentry_sdk/integrations/google_genai/streaming.py b/sentry_sdk/integrations/google_genai/streaming.py index 3f44585f82..23e6b90c0c 100644 --- a/sentry_sdk/integrations/google_genai/streaming.py +++ b/sentry_sdk/integrations/google_genai/streaming.py @@ -131,7 +131,7 @@ def set_span_data_for_streaming_response( if accumulated_response["usage_metadata"]["input_tokens_cached"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, accumulated_response["usage_metadata"]["input_tokens_cached"], ) diff --git a/sentry_sdk/integrations/google_genai/utils.py b/sentry_sdk/integrations/google_genai/utils.py index 5def5be34c..83034bd90f 100644 --- a/sentry_sdk/integrations/google_genai/utils.py +++ b/sentry_sdk/integrations/google_genai/utils.py @@ -1023,7 +1023,7 @@ def set_span_data_for_response( if usage_data["input_tokens_cached"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage_data["input_tokens_cached"], ) diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index c27cea970e..37aacf51cc 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -93,7 +93,7 @@ def _set_agent_data(span: "StreamedSpan", agent: "agents.Agent") -> None: def _set_usage_data(span: "StreamedSpan", usage: "Usage") -> None: span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) span.set_attribute( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage.input_tokens_details.cached_tokens, ) span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) diff --git a/sentry_sdk/integrations/pydantic_ai/spans/utils.py b/sentry_sdk/integrations/pydantic_ai/spans/utils.py index cbce0c0c77..1058bfecc2 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/utils.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/utils.py @@ -71,7 +71,9 @@ def _set_usage_data( # Pydantic AI uses cache_read_tokens (not input_tokens_cached) if hasattr(usage, "cache_read_tokens") and usage.cache_read_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, usage.cache_read_tokens) + set_on_span( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage.cache_read_tokens + ) # Pydantic AI uses cache_write_tokens (not input_tokens_cache_write) if hasattr(usage, "cache_write_tokens") and usage.cache_write_tokens is not None: diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py index eef7771359..ba69dbcd3f 100644 --- a/tests/integrations/anthropic/test_anthropic.py +++ b/tests/integrations/anthropic/test_anthropic.py @@ -4960,7 +4960,7 @@ def test_cache_tokens_nonstreaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 50 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 250 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 @@ -5017,7 +5017,7 @@ def test_input_tokens_include_cache_write_nonstreaming( # input_tokens should be total: 19 (non-cached) + 2846 (cache_write) = 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 0 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 2846 @@ -5074,7 +5074,7 @@ def test_input_tokens_include_cache_read_nonstreaming( # input_tokens should be total: 19 (non-cached) + 2846 (cache_read) = 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 @@ -5146,7 +5146,7 @@ def test_input_tokens_include_cache_read_streaming( # input_tokens should be total: 19 + 2846 = test_stream_messages_input_tokens_include_cache_read_streaming assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 @@ -5216,7 +5216,7 @@ def test_stream_messages_input_tokens_include_cache_read_streaming( # input_tokens should be total: 19 + 2846 = 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 @@ -5331,7 +5331,7 @@ def test_cache_tokens_streaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 @@ -5398,5 +5398,5 @@ def test_stream_messages_cache_tokens( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 diff --git a/tests/integrations/google_genai/test_google_genai.py b/tests/integrations/google_genai/test_google_genai.py index 845d7a971e..2b33671bf8 100644 --- a/tests/integrations/google_genai/test_google_genai.py +++ b/tests/integrations/google_genai/test_google_genai.py @@ -201,7 +201,7 @@ def test_nonstreaming_generate_content( # Output tokens now include reasoning tokens: candidates_token_count (20) + thoughts_token_count (3) = 23 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 @@ -582,7 +582,7 @@ def test_streaming_generate_content( assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 # Verify model name diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index aa527b17b4..96b49adf3a 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -3682,7 +3682,7 @@ def test_ai_client_span_responses_api_no_pii( "gen_ai.response.streaming": False, "gen_ai.system": "openai", "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, "gen_ai.usage.output_tokens.reasoning": 8, "gen_ai.usage.total_tokens": 30, @@ -3955,7 +3955,7 @@ def test_ai_client_span_responses_api( "gen_ai.response.model": "response-model-id", "gen_ai.response.streaming": False, "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, "gen_ai.usage.output_tokens.reasoning": 8, "gen_ai.usage.total_tokens": 30, @@ -4765,7 +4765,7 @@ async def test_ai_client_span_responses_async_api( "gen_ai.response.streaming": False, "gen_ai.system": "openai", "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, "gen_ai.usage.output_tokens.reasoning": 8, "gen_ai.usage.total_tokens": 30, @@ -4993,7 +4993,7 @@ async def test_ai_client_span_streaming_responses_async_api( "gen_ai.system": "openai", "gen_ai.response.time_to_first_token": mock.ANY, "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, "gen_ai.usage.output_tokens.reasoning": 8, "gen_ai.usage.total_tokens": 30, diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index b47659fadd..ff00c4c988 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -2069,7 +2069,10 @@ async def test_tool_execution_span( assert ai_client_span1["attributes"]["gen_ai.request.temperature"] == 0.7 assert ai_client_span1["attributes"]["gen_ai.request.top_p"] == 1.0 assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 + assert ( + ai_client_span1["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens"] == 5 assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 assert ai_client_span1["attributes"]["gen_ai.usage.total_tokens"] == 15 @@ -2158,7 +2161,10 @@ async def test_tool_execution_span( == "Task completed using the tool" ) assert ai_client_span2["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 + assert ( + ai_client_span2["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens"] == 15 assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens"] == 10 @@ -3400,7 +3406,10 @@ async def test_invoke_agent_span_includes_usage_data( assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 10 assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 5 @@ -3711,7 +3720,10 @@ def calculator(a: int, b: int) -> int: assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 50 # Cached tokens should be aggregated: 0 + 5 = 5 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 5 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 5 + ) # Reasoning tokens should be aggregated: 0 + 3 = 3 assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 3 diff --git a/tests/integrations/pydantic_ai/test_pydantic_ai.py b/tests/integrations/pydantic_ai/test_pydantic_ai.py index 23d7da8b76..ed54facac5 100644 --- a/tests/integrations/pydantic_ai/test_pydantic_ai.py +++ b/tests/integrations/pydantic_ai/test_pydantic_ai.py @@ -2706,7 +2706,7 @@ async def test_set_usage_data_with_cache_tokens( sentry_sdk.flush() spans = [item.payload for item in items] - assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 + assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 From 5ae3e2b97c4224339bc98a9ec962ce3efad53eda Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 11 Sep 2026 13:31:32 +0200 Subject: [PATCH 2/4] Replace gen_ai.usage.input_tokens.cache_write with gen_ai.usage.cache_creation.input_tokens --- sentry_sdk/ai/monitoring.py | 2 +- sentry_sdk/integrations/pydantic_ai/spans/utils.py | 2 +- tests/integrations/anthropic/test_anthropic.py | 14 +++++++------- tests/integrations/pydantic_ai/test_pydantic_ai.py | 4 +++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/sentry_sdk/ai/monitoring.py b/sentry_sdk/ai/monitoring.py index 9657d82ad4..a3327e8933 100644 --- a/sentry_sdk/ai/monitoring.py +++ b/sentry_sdk/ai/monitoring.py @@ -33,7 +33,7 @@ def record_token_usage( if input_tokens_cache_write is not None: _set_span_data_attribute( span, - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, + SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, input_tokens_cache_write, ) diff --git a/sentry_sdk/integrations/pydantic_ai/spans/utils.py b/sentry_sdk/integrations/pydantic_ai/spans/utils.py index 1058bfecc2..392807d90a 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/utils.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/utils.py @@ -78,7 +78,7 @@ def _set_usage_data( # Pydantic AI uses cache_write_tokens (not input_tokens_cache_write) if hasattr(usage, "cache_write_tokens") and usage.cache_write_tokens is not None: set_on_span( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, + SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, usage.cache_write_tokens, ) diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py index ba69dbcd3f..be6b45a4bf 100644 --- a/tests/integrations/anthropic/test_anthropic.py +++ b/tests/integrations/anthropic/test_anthropic.py @@ -4961,7 +4961,7 @@ def test_cache_tokens_nonstreaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 50 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 250 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 def test_input_tokens_include_cache_write_nonstreaming( @@ -5018,7 +5018,7 @@ def test_input_tokens_include_cache_write_nonstreaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 0 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 2846 def test_input_tokens_include_cache_read_nonstreaming( @@ -5075,7 +5075,7 @@ def test_input_tokens_include_cache_read_nonstreaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 def test_input_tokens_include_cache_read_streaming( @@ -5147,7 +5147,7 @@ def test_input_tokens_include_cache_read_streaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 def test_stream_messages_input_tokens_include_cache_read_streaming( @@ -5217,7 +5217,7 @@ def test_stream_messages_input_tokens_include_cache_read_streaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 def test_input_tokens_unchanged_without_caching( @@ -5332,7 +5332,7 @@ def test_cache_tokens_streaming( assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 def test_stream_messages_cache_tokens( @@ -5399,4 +5399,4 @@ def test_stream_messages_cache_tokens( assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 diff --git a/tests/integrations/pydantic_ai/test_pydantic_ai.py b/tests/integrations/pydantic_ai/test_pydantic_ai.py index ed54facac5..8603afbd85 100644 --- a/tests/integrations/pydantic_ai/test_pydantic_ai.py +++ b/tests/integrations/pydantic_ai/test_pydantic_ai.py @@ -2707,7 +2707,9 @@ async def test_set_usage_data_with_cache_tokens( spans = [item.payload for item in items] assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 - assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert ( + spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 + ) @pytest.mark.parametrize( From 073f43c0081a6c34544bad4337175aa580ba50d0 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 11 Sep 2026 13:38:42 +0200 Subject: [PATCH 3/4] Replace gen_ai.usage.reasoning.output_tokens with gen_ai.usage.output_tokens.reasoning --- sentry_sdk/ai/monitoring.py | 2 +- sentry_sdk/integrations/google_genai/streaming.py | 2 +- sentry_sdk/integrations/google_genai/utils.py | 2 +- sentry_sdk/integrations/openai_agents/utils.py | 2 +- tests/integrations/google_genai/test_google_genai.py | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sentry_sdk/ai/monitoring.py b/sentry_sdk/ai/monitoring.py index a3327e8933..b30ba6d155 100644 --- a/sentry_sdk/ai/monitoring.py +++ b/sentry_sdk/ai/monitoring.py @@ -45,7 +45,7 @@ def record_token_usage( if output_tokens_reasoning is not None: _set_span_data_attribute( span, - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, output_tokens_reasoning, ) diff --git a/sentry_sdk/integrations/google_genai/streaming.py b/sentry_sdk/integrations/google_genai/streaming.py index 23e6b90c0c..e8e329e662 100644 --- a/sentry_sdk/integrations/google_genai/streaming.py +++ b/sentry_sdk/integrations/google_genai/streaming.py @@ -143,7 +143,7 @@ def set_span_data_for_streaming_response( if accumulated_response["usage_metadata"]["output_tokens_reasoning"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, accumulated_response["usage_metadata"]["output_tokens_reasoning"], ) diff --git a/sentry_sdk/integrations/google_genai/utils.py b/sentry_sdk/integrations/google_genai/utils.py index 83034bd90f..7c7e5ee57d 100644 --- a/sentry_sdk/integrations/google_genai/utils.py +++ b/sentry_sdk/integrations/google_genai/utils.py @@ -1034,7 +1034,7 @@ def set_span_data_for_response( if usage_data["output_tokens_reasoning"]: span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, usage_data["output_tokens_reasoning"], ) diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index 37aacf51cc..b0ad93b7b2 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -98,7 +98,7 @@ def _set_usage_data(span: "StreamedSpan", usage: "Usage") -> None: ) span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) span.set_attribute( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, usage.output_tokens_details.reasoning_tokens, ) span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) diff --git a/tests/integrations/google_genai/test_google_genai.py b/tests/integrations/google_genai/test_google_genai.py index 2b33671bf8..09a66dd610 100644 --- a/tests/integrations/google_genai/test_google_genai.py +++ b/tests/integrations/google_genai/test_google_genai.py @@ -202,7 +202,7 @@ def test_nonstreaming_generate_content( assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 3 @pytest.mark.parametrize("generate_content_config", (False, True)) @@ -583,7 +583,7 @@ def test_streaming_generate_content( assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 3 # Verify model name assert chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" From 582566b74c6543a2dab1402c3ec91f90488c6b8f Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 11 Sep 2026 13:48:22 +0200 Subject: [PATCH 4/4] update gen_ai.usage.output_tokens.reasoning constant strings --- tests/integrations/openai/test_openai.py | 8 ++++---- .../openai_agents/test_openai_agents.py | 20 +++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 96b49adf3a..4510b96fff 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -3684,7 +3684,7 @@ def test_ai_client_span_responses_api_no_pii( "gen_ai.usage.input_tokens": 20, SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "sentry.op": "gen_ai.responses", "sentry.origin": "auto.ai.openai", @@ -3957,7 +3957,7 @@ def test_ai_client_span_responses_api( "gen_ai.usage.input_tokens": 20, SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.request.messages": safe_serialize(expected_request_messages), "gen_ai.request.model": "gpt-4o", @@ -4767,7 +4767,7 @@ async def test_ai_client_span_responses_async_api( "gen_ai.usage.input_tokens": 20, SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.response.text": "the model response", "sentry.op": "gen_ai.responses", @@ -4995,7 +4995,7 @@ async def test_ai_client_span_streaming_responses_async_api( "gen_ai.usage.input_tokens": 20, SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, "gen_ai.usage.total_tokens": 30, "gen_ai.request.model": "gpt-4o", "gen_ai.response.text": "hello world", diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index ff00c4c988..28403a8f29 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -2074,7 +2074,10 @@ async def test_tool_execution_span( == 0 ) assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens"] == 5 - assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 + assert ( + ai_client_span1["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 0 + ) assert ai_client_span1["attributes"]["gen_ai.usage.total_tokens"] == 15 tool_call = { @@ -2166,7 +2169,10 @@ async def test_tool_execution_span( == 0 ) assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens"] == 15 - assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 + assert ( + ai_client_span2["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 0 + ) assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens"] == 10 assert ai_client_span2["attributes"]["gen_ai.usage.total_tokens"] == 25 @@ -3410,7 +3416,10 @@ async def test_invoke_agent_span_includes_usage_data( invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 0 ) - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 5 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 5 + ) @pytest.mark.asyncio @@ -3725,7 +3734,10 @@ def calculator(a: int, b: int) -> int: == 5 ) # Reasoning tokens should be aggregated: 0 + 3 = 3 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 3 + assert ( + invoke_agent_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 3 + ) @pytest.mark.asyncio