Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions agentops/instrumentation/common/token_counting.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ def to_attributes(self) -> Dict[str, int]:

if self.prompt_tokens:
attributes[SpanAttributes.LLM_USAGE_PROMPT_TOKENS] = self.prompt_tokens
# Dual-emit current OTel GenAI names so mixed-SDK collectors can sum either family.
attributes[SpanAttributes.LLM_USAGE_INPUT_TOKENS] = self.prompt_tokens

if self.completion_tokens:
attributes[SpanAttributes.LLM_USAGE_COMPLETION_TOKENS] = self.completion_tokens
attributes[SpanAttributes.LLM_USAGE_OUTPUT_TOKENS] = self.completion_tokens

if self.total_tokens:
attributes[SpanAttributes.LLM_USAGE_TOTAL_TOKENS] = self.total_tokens
Expand Down
4 changes: 4 additions & 0 deletions agentops/semconv/span_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ class SpanAttributes:
LLM_RESPONSE_ID = "gen_ai.response.id"

# Usage metrics
# Legacy GenAI names still emitted by AgentOps; current OTel GenAI names are
# dual-emitted during the transition (#1447).
LLM_USAGE_COMPLETION_TOKENS = "gen_ai.usage.completion_tokens"
LLM_USAGE_PROMPT_TOKENS = "gen_ai.usage.prompt_tokens"
LLM_USAGE_INPUT_TOKENS = "gen_ai.usage.input_tokens"
LLM_USAGE_OUTPUT_TOKENS = "gen_ai.usage.output_tokens"
LLM_USAGE_TOTAL_TOKENS = "gen_ai.usage.total_tokens"
LLM_USAGE_CACHE_CREATION_INPUT_TOKENS = "gen_ai.usage.cache_creation_input_tokens"
LLM_USAGE_CACHE_READ_INPUT_TOKENS = "gen_ai.usage.cache_read_input_tokens"
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/instrumentation/common/test_token_counting.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ def test_includes_positive_values_only(self):
attrs = usage.to_attributes()
assert SpanAttributes.LLM_USAGE_PROMPT_TOKENS in attrs
assert attrs[SpanAttributes.LLM_USAGE_PROMPT_TOKENS] == 5
assert SpanAttributes.LLM_USAGE_INPUT_TOKENS in attrs
assert attrs[SpanAttributes.LLM_USAGE_INPUT_TOKENS] == 5
assert SpanAttributes.LLM_USAGE_COMPLETION_TOKENS not in attrs
assert SpanAttributes.LLM_USAGE_OUTPUT_TOKENS not in attrs
assert SpanAttributes.LLM_USAGE_TOTAL_TOKENS in attrs
assert attrs[SpanAttributes.LLM_USAGE_TOTAL_TOKENS] == 5

def test_dual_emits_current_otel_genai_names(self):
usage = TokenUsage(prompt_tokens=10, completion_tokens=4, total_tokens=14)
attrs = usage.to_attributes()
assert attrs[SpanAttributes.LLM_USAGE_PROMPT_TOKENS] == 10
assert attrs[SpanAttributes.LLM_USAGE_INPUT_TOKENS] == 10
assert attrs[SpanAttributes.LLM_USAGE_COMPLETION_TOKENS] == 4
assert attrs[SpanAttributes.LLM_USAGE_OUTPUT_TOKENS] == 4
assert attrs[SpanAttributes.LLM_USAGE_TOTAL_TOKENS] == 14