From 09a03edc49a89ee6e216460a7216a00d95b9f29f Mon Sep 17 00:00:00 2001 From: Matej Minar Date: Thu, 21 May 2026 10:37:51 +0200 Subject: [PATCH] feat(attributes): Add additional_context to gen_ai cost and usage attributes Populates the `additional_context` field (introduced in #393) for all 11 gen_ai cost and usage attributes. Each attribute gets notes about: - Double-counting: all cost/usage attributes appear on both agent parent spans (aggregated totals) and LLM child spans (per-call values). Summing without filtering to gen_ai.operation.type:ai_client will over-report. - Naming confusion: cost attributes contain USD values despite having "tokens" in the name. - Subset relationships: cached input tokens are a subset of input tokens, reasoning tokens are a subset of output tokens, and total tokens is the sum of input + output. These should not be summed together. Attributes updated: - gen_ai.cost.input_tokens, gen_ai.cost.output_tokens, gen_ai.cost.total_tokens - gen_ai.usage.input_tokens, gen_ai.usage.input_tokens.cached, gen_ai.usage.input_tokens.cache_write - gen_ai.usage.output_tokens, gen_ai.usage.output_tokens.reasoning - gen_ai.usage.total_tokens - gen_ai.usage.completion_tokens (deprecated), gen_ai.usage.prompt_tokens (deprecated) --- .../sentry-conventions/src/attributes.ts | 70 ++++++++++++++++- .../gen_ai/gen_ai__cost__input_tokens.json | 10 +++ .../gen_ai/gen_ai__cost__output_tokens.json | 10 +++ .../gen_ai/gen_ai__cost__total_tokens.json | 9 +++ .../gen_ai__usage__completion_tokens.json | 8 ++ .../gen_ai/gen_ai__usage__input_tokens.json | 9 +++ ..._ai__usage__input_tokens__cache_write.json | 8 ++ .../gen_ai__usage__input_tokens__cached.json | 9 +++ .../gen_ai/gen_ai__usage__output_tokens.json | 9 +++ ...n_ai__usage__output_tokens__reasoning.json | 9 +++ .../gen_ai/gen_ai__usage__prompt_tokens.json | 8 ++ .../gen_ai/gen_ai__usage__total_tokens.json | 9 +++ python/src/sentry_conventions/attributes.py | 76 +++++++++++++++++++ shared/deprecated_attributes.json | 16 ++++ 14 files changed, 257 insertions(+), 3 deletions(-) diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts index 71820f4c..9530ab38 100644 --- a/javascript/sentry-conventions/src/attributes.ts +++ b/javascript/sentry-conventions/src/attributes.ts @@ -17430,9 +17430,15 @@ export const ATTRIBUTE_METADATA: Record = { visibility: 'public', example: 123.45, changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [112] }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + "Despite the name 'cost.input_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.input_tokens.", + 'This is the cost of non-cached input tokens only. The cost of cached tokens is excluded from this value.', + ], }, [GEN_AI_COST_OUTPUT_TOKENS]: { brief: 'The cost of tokens used for creating the AI output in USD (without reasoning tokens).', @@ -17444,9 +17450,15 @@ export const ATTRIBUTE_METADATA: Record = { visibility: 'public', example: 123.45, changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [112] }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + "Despite the name 'cost.output_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.output_tokens.", + 'This is the cost of non-reasoning output tokens only. The cost of reasoning tokens is excluded from this value.', + ], }, [GEN_AI_COST_TOTAL_TOKENS]: { brief: 'The total cost for the tokens used.', @@ -17459,10 +17471,15 @@ export const ATTRIBUTE_METADATA: Record = { example: 12.34, aliases: [AI_TOTAL_COST], changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.5.0', prs: [264] }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [126] }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + "Despite the name 'cost.total_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.total_tokens.", + ], }, [GEN_AI_EMBEDDINGS_INPUT]: { brief: 'The input to the embeddings model.', @@ -18045,7 +18062,15 @@ export const ATTRIBUTE_METADATA: Record = { replacement: 'gen_ai.usage.output_tokens', }, aliases: [AI_COMPLETION_TOKENS_USED, GEN_AI_USAGE_OUTPUT_TOKENS], - changelog: [{ version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [61] }, { version: '0.0.0' }], + changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, + { version: '0.4.0', prs: [228] }, + { version: '0.1.0', prs: [61] }, + { version: '0.0.0' }, + ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + ], }, [GEN_AI_USAGE_INPUT_TOKENS]: { brief: 'The number of tokens used to process the AI input (prompt) including cached input tokens.', @@ -18058,11 +18083,16 @@ export const ATTRIBUTE_METADATA: Record = { example: 10, aliases: [AI_PROMPT_TOKENS_USED, GEN_AI_USAGE_PROMPT_TOKENS], changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.5.0', prs: [261] }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [112] }, { version: '0.0.0' }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + 'This count includes cached input tokens. gen_ai.usage.input_tokens.cached is a subset of this value, not an independent count — do not sum them together.', + ], }, [GEN_AI_USAGE_INPUT_TOKENS_CACHED]: { brief: 'The number of cached tokens used to process the AI input (prompt).', @@ -18074,9 +18104,14 @@ export const ATTRIBUTE_METADATA: Record = { visibility: 'public', example: 50, changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [62, 112] }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + 'This is a subset of gen_ai.usage.input_tokens, not an independent count. Do not sum this with gen_ai.usage.input_tokens — it is already included.', + ], }, [GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE]: { brief: 'The number of tokens written to the cache when processing the AI input (prompt).', @@ -18087,7 +18122,13 @@ export const ATTRIBUTE_METADATA: Record = { isInOtel: false, visibility: 'public', example: 100, - changelog: [{ version: '0.4.0', prs: [217, 228] }], + changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, + { version: '0.4.0', prs: [217, 228] }, + ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + ], }, [GEN_AI_USAGE_OUTPUT_TOKENS]: { brief: 'The number of tokens used for creating the AI output (including reasoning tokens).', @@ -18100,11 +18141,16 @@ export const ATTRIBUTE_METADATA: Record = { example: 10, aliases: [AI_COMPLETION_TOKENS_USED, GEN_AI_USAGE_COMPLETION_TOKENS], changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.5.0', prs: [261] }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [112] }, { version: '0.0.0' }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + 'This count includes reasoning tokens. gen_ai.usage.output_tokens.reasoning is a subset of this value, not an independent count — do not sum them together.', + ], }, [GEN_AI_USAGE_OUTPUT_TOKENS_REASONING]: { brief: 'The number of tokens used for reasoning to create the AI output.', @@ -18116,9 +18162,14 @@ export const ATTRIBUTE_METADATA: Record = { visibility: 'public', example: 75, changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [62, 112] }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + 'This is a subset of gen_ai.usage.output_tokens, not an independent count. Do not sum this with gen_ai.usage.output_tokens — it is already included.', + ], }, [GEN_AI_USAGE_PROMPT_TOKENS]: { brief: 'The number of tokens used in the GenAI input (prompt).', @@ -18133,7 +18184,15 @@ export const ATTRIBUTE_METADATA: Record = { replacement: 'gen_ai.usage.input_tokens', }, aliases: [AI_PROMPT_TOKENS_USED, GEN_AI_USAGE_INPUT_TOKENS], - changelog: [{ version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [61] }, { version: '0.0.0' }], + changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, + { version: '0.4.0', prs: [228] }, + { version: '0.1.0', prs: [61] }, + { version: '0.0.0' }, + ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + ], }, [GEN_AI_USAGE_TOTAL_TOKENS]: { brief: 'The total number of tokens used to process the prompt. (input tokens plus output todkens)', @@ -18146,9 +18205,14 @@ export const ATTRIBUTE_METADATA: Record = { example: 20, aliases: [AI_TOTAL_TOKENS_USED], changelog: [ + { version: 'next', prs: [397], description: 'Add additional_context' }, { version: '0.4.0', prs: [228] }, { version: '0.1.0', prs: [57] }, ], + additionalContext: [ + 'This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.', + 'This is the sum of gen_ai.usage.input_tokens and gen_ai.usage.output_tokens. Do not sum this with either of them — they are already included.', + ], }, [GRAPHQL_DOCUMENT]: { brief: 'The GraphQL document being executed.', diff --git a/model/attributes/gen_ai/gen_ai__cost__input_tokens.json b/model/attributes/gen_ai/gen_ai__cost__input_tokens.json index a275fe66..c98b608f 100644 --- a/model/attributes/gen_ai/gen_ai__cost__input_tokens.json +++ b/model/attributes/gen_ai/gen_ai__cost__input_tokens.json @@ -8,7 +8,17 @@ "is_in_otel": false, "example": 123.45, "visibility": "public", + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "Despite the name 'cost.input_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.input_tokens.", + "This is the cost of non-cached input tokens only. The cost of cached tokens is excluded from this value." + ], "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/model/attributes/gen_ai/gen_ai__cost__output_tokens.json b/model/attributes/gen_ai/gen_ai__cost__output_tokens.json index 21b638b8..3bcdca67 100644 --- a/model/attributes/gen_ai/gen_ai__cost__output_tokens.json +++ b/model/attributes/gen_ai/gen_ai__cost__output_tokens.json @@ -8,7 +8,17 @@ "is_in_otel": false, "example": 123.45, "visibility": "public", + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "Despite the name 'cost.output_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.output_tokens.", + "This is the cost of non-reasoning output tokens only. The cost of reasoning tokens is excluded from this value." + ], "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/model/attributes/gen_ai/gen_ai__cost__total_tokens.json b/model/attributes/gen_ai/gen_ai__cost__total_tokens.json index e096b479..97206de7 100644 --- a/model/attributes/gen_ai/gen_ai__cost__total_tokens.json +++ b/model/attributes/gen_ai/gen_ai__cost__total_tokens.json @@ -7,9 +7,18 @@ }, "is_in_otel": false, "example": 12.34, + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "Despite the name 'cost.total_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.total_tokens." + ], "alias": ["ai.total_cost"], "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.5.0", "prs": [264] diff --git a/model/attributes/gen_ai/gen_ai__usage__completion_tokens.json b/model/attributes/gen_ai/gen_ai__usage__completion_tokens.json index db63eaa4..9f77d92c 100644 --- a/model/attributes/gen_ai/gen_ai__usage__completion_tokens.json +++ b/model/attributes/gen_ai/gen_ai__usage__completion_tokens.json @@ -8,12 +8,20 @@ "is_in_otel": true, "example": 10, "alias": ["ai.completion_tokens.used", "gen_ai.usage.output_tokens"], + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], "deprecation": { "_status": "backfill", "replacement": "gen_ai.usage.output_tokens" }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/model/attributes/gen_ai/gen_ai__usage__input_tokens.json b/model/attributes/gen_ai/gen_ai__usage__input_tokens.json index 4d0511ca..5e65c6ce 100644 --- a/model/attributes/gen_ai/gen_ai__usage__input_tokens.json +++ b/model/attributes/gen_ai/gen_ai__usage__input_tokens.json @@ -7,9 +7,18 @@ }, "is_in_otel": true, "example": 10, + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This count includes cached input tokens. gen_ai.usage.input_tokens.cached is a subset of this value, not an independent count \u2014 do not sum them together." + ], "alias": ["ai.prompt_tokens.used", "gen_ai.usage.prompt_tokens"], "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.5.0", "prs": [261] diff --git a/model/attributes/gen_ai/gen_ai__usage__input_tokens__cache_write.json b/model/attributes/gen_ai/gen_ai__usage__input_tokens__cache_write.json index fd053448..1f2fa245 100644 --- a/model/attributes/gen_ai/gen_ai__usage__input_tokens__cache_write.json +++ b/model/attributes/gen_ai/gen_ai__usage__input_tokens__cache_write.json @@ -8,7 +8,15 @@ "is_in_otel": false, "example": 100, "visibility": "public", + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [217, 228] diff --git a/model/attributes/gen_ai/gen_ai__usage__input_tokens__cached.json b/model/attributes/gen_ai/gen_ai__usage__input_tokens__cached.json index f691f3d1..72d4be45 100644 --- a/model/attributes/gen_ai/gen_ai__usage__input_tokens__cached.json +++ b/model/attributes/gen_ai/gen_ai__usage__input_tokens__cached.json @@ -8,7 +8,16 @@ "is_in_otel": false, "example": 50, "visibility": "public", + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This is a subset of gen_ai.usage.input_tokens, not an independent count. Do not sum this with gen_ai.usage.input_tokens \u2014 it is already included." + ], "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/model/attributes/gen_ai/gen_ai__usage__output_tokens.json b/model/attributes/gen_ai/gen_ai__usage__output_tokens.json index 3e2d36f0..ec7c1d24 100644 --- a/model/attributes/gen_ai/gen_ai__usage__output_tokens.json +++ b/model/attributes/gen_ai/gen_ai__usage__output_tokens.json @@ -7,9 +7,18 @@ }, "is_in_otel": true, "example": 10, + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This count includes reasoning tokens. gen_ai.usage.output_tokens.reasoning is a subset of this value, not an independent count \u2014 do not sum them together." + ], "alias": ["ai.completion_tokens.used", "gen_ai.usage.completion_tokens"], "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.5.0", "prs": [261] diff --git a/model/attributes/gen_ai/gen_ai__usage__output_tokens__reasoning.json b/model/attributes/gen_ai/gen_ai__usage__output_tokens__reasoning.json index 9d2b53ef..321f2e2a 100644 --- a/model/attributes/gen_ai/gen_ai__usage__output_tokens__reasoning.json +++ b/model/attributes/gen_ai/gen_ai__usage__output_tokens__reasoning.json @@ -8,7 +8,16 @@ "is_in_otel": false, "example": 75, "visibility": "public", + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This is a subset of gen_ai.usage.output_tokens, not an independent count. Do not sum this with gen_ai.usage.output_tokens \u2014 it is already included." + ], "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/model/attributes/gen_ai/gen_ai__usage__prompt_tokens.json b/model/attributes/gen_ai/gen_ai__usage__prompt_tokens.json index cbc66907..ea9916a7 100644 --- a/model/attributes/gen_ai/gen_ai__usage__prompt_tokens.json +++ b/model/attributes/gen_ai/gen_ai__usage__prompt_tokens.json @@ -8,12 +8,20 @@ "is_in_otel": true, "example": 20, "alias": ["ai.prompt_tokens.used", "gen_ai.usage.input_tokens"], + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], "deprecation": { "_status": "backfill", "replacement": "gen_ai.usage.input_tokens" }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/model/attributes/gen_ai/gen_ai__usage__total_tokens.json b/model/attributes/gen_ai/gen_ai__usage__total_tokens.json index f68c3e72..76204d56 100644 --- a/model/attributes/gen_ai/gen_ai__usage__total_tokens.json +++ b/model/attributes/gen_ai/gen_ai__usage__total_tokens.json @@ -7,9 +7,18 @@ }, "is_in_otel": false, "example": 20, + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This is the sum of gen_ai.usage.input_tokens and gen_ai.usage.output_tokens. Do not sum this with either of them \u2014 they are already included." + ], "alias": ["ai.total_tokens.used"], "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] diff --git a/python/src/sentry_conventions/attributes.py b/python/src/sentry_conventions/attributes.py index 9ad8cf4e..570c5375 100644 --- a/python/src/sentry_conventions/attributes.py +++ b/python/src/sentry_conventions/attributes.py @@ -10955,9 +10955,17 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): visibility=Visibility.PUBLIC, example=123.45, changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[112]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "Despite the name 'cost.input_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.input_tokens.", + "This is the cost of non-cached input tokens only. The cost of cached tokens is excluded from this value.", + ], ), "gen_ai.cost.output_tokens": AttributeMetadata( brief="The cost of tokens used for creating the AI output in USD (without reasoning tokens).", @@ -10967,9 +10975,17 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): visibility=Visibility.PUBLIC, example=123.45, changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[112]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "Despite the name 'cost.output_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.output_tokens.", + "This is the cost of non-reasoning output tokens only. The cost of reasoning tokens is excluded from this value.", + ], ), "gen_ai.cost.total_tokens": AttributeMetadata( brief="The total cost for the tokens used.", @@ -10980,10 +10996,17 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): example=12.34, aliases=["ai.total_cost"], changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.5.0", prs=[264]), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[126]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to calculate total cost, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "Despite the name 'cost.total_tokens', this value is cost in USD, not a token count. For token counts, use gen_ai.usage.total_tokens.", + ], ), "gen_ai.embeddings.input": AttributeMetadata( brief="The input to the embeddings model.", @@ -11509,10 +11532,16 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): ), aliases=["ai.completion_tokens.used", "gen_ai.usage.output_tokens"], changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[61]), ChangelogEntry(version="0.0.0"), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], ), "gen_ai.usage.input_tokens": AttributeMetadata( brief="The number of tokens used to process the AI input (prompt) including cached input tokens.", @@ -11523,11 +11552,18 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): example=10, aliases=["ai.prompt_tokens.used", "gen_ai.usage.prompt_tokens"], changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.5.0", prs=[261]), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[112]), ChangelogEntry(version="0.0.0"), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This count includes cached input tokens. gen_ai.usage.input_tokens.cached is a subset of this value, not an independent count — do not sum them together.", + ], ), "gen_ai.usage.input_tokens.cache_write": AttributeMetadata( brief="The number of tokens written to the cache when processing the AI input (prompt).", @@ -11537,8 +11573,14 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): visibility=Visibility.PUBLIC, example=100, changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[217, 228]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], ), "gen_ai.usage.input_tokens.cached": AttributeMetadata( brief="The number of cached tokens used to process the AI input (prompt).", @@ -11548,9 +11590,16 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): visibility=Visibility.PUBLIC, example=50, changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[62, 112]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This is a subset of gen_ai.usage.input_tokens, not an independent count. Do not sum this with gen_ai.usage.input_tokens — it is already included.", + ], ), "gen_ai.usage.output_tokens": AttributeMetadata( brief="The number of tokens used for creating the AI output (including reasoning tokens).", @@ -11561,11 +11610,18 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): example=10, aliases=["ai.completion_tokens.used", "gen_ai.usage.completion_tokens"], changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.5.0", prs=[261]), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[112]), ChangelogEntry(version="0.0.0"), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This count includes reasoning tokens. gen_ai.usage.output_tokens.reasoning is a subset of this value, not an independent count — do not sum them together.", + ], ), "gen_ai.usage.output_tokens.reasoning": AttributeMetadata( brief="The number of tokens used for reasoning to create the AI output.", @@ -11575,9 +11631,16 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): visibility=Visibility.PUBLIC, example=75, changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[62, 112]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This is a subset of gen_ai.usage.output_tokens, not an independent count. Do not sum this with gen_ai.usage.output_tokens — it is already included.", + ], ), "gen_ai.usage.prompt_tokens": AttributeMetadata( brief="The number of tokens used in the GenAI input (prompt).", @@ -11591,10 +11654,16 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): ), aliases=["ai.prompt_tokens.used", "gen_ai.usage.input_tokens"], changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[61]), ChangelogEntry(version="0.0.0"), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], ), "gen_ai.usage.total_tokens": AttributeMetadata( brief="The total number of tokens used to process the prompt. (input tokens plus output todkens)", @@ -11605,9 +11674,16 @@ class ATTRIBUTE_NAMES(metaclass=_AttributeNamesMeta): example=20, aliases=["ai.total_tokens.used"], changelog=[ + ChangelogEntry( + version="next", prs=[397], description="Add additional_context" + ), ChangelogEntry(version="0.4.0", prs=[228]), ChangelogEntry(version="0.1.0", prs=[57]), ], + additional_context=[ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans.", + "This is the sum of gen_ai.usage.input_tokens and gen_ai.usage.output_tokens. Do not sum this with either of them — they are already included.", + ], ), "graphql.document": AttributeMetadata( brief="The GraphQL document being executed.", diff --git a/shared/deprecated_attributes.json b/shared/deprecated_attributes.json index 707cde70..7f1172d5 100644 --- a/shared/deprecated_attributes.json +++ b/shared/deprecated_attributes.json @@ -2214,12 +2214,20 @@ "is_in_otel": true, "example": 10, "alias": ["ai.completion_tokens.used", "gen_ai.usage.output_tokens"], + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], "deprecation": { "_status": "backfill", "replacement": "gen_ai.usage.output_tokens" }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228] @@ -2243,12 +2251,20 @@ "is_in_otel": true, "example": 20, "alias": ["ai.prompt_tokens.used", "gen_ai.usage.input_tokens"], + "additional_context": [ + "This attribute appears on both agent parent spans (aggregated totals) and LLM child spans (per-call values). When using sum() to count tokens, filter to gen_ai.operation.type:ai_client to avoid double-counting hierarchical spans." + ], "deprecation": { "_status": "backfill", "replacement": "gen_ai.usage.input_tokens" }, "visibility": "public", "changelog": [ + { + "version": "next", + "prs": [397], + "description": "Add additional_context" + }, { "version": "0.4.0", "prs": [228]