Observed since 20 Oct, 22:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Normalization layer for OpenTelemetry GenAI agent traces. Single parsing pass, framework detection, span classification with confidence scores.
Normalization layer for OpenTelemetry GenAI agent traces. Parse once, analyze anywhere.
pip install agentic-otel
Every tool that analyzes AI agent traces re-implements the same parsing: span extraction, root finding, attribute parsing, timestamp handling, span classification. And every agent framework emits slightly different OTEL: camelCase vs. snake_case keys, KV-list vs. dict attributes, content in span attributes vs. span events, different operation names.
agentic-otel does that parsing once, correctly, with zero runtime dependencies — so trace-analysis tools can start from a consistent representation instead of raw JSON.
from agentic_otel import (
extract_spans, # OTLP resourceSpans or flat {"spans": [...]} -> list of span dicts
find_root, # locate the root span (parent-less, or earliest fallback)
parse_attrs, # KV-list or dict attributes -> flat dict
parse_timestamp, # unix nanos (int or str) -> datetime
DEFAULT_REGISTRY, # span classification rules
)
spans = extract_spans(raw_trace_json)
root = find_root(spans)
for span in spans:
result = DEFAULT_REGISTRY.classify(span)
print(span.get("name"), "->", result.span_type, f"(confidence: {result.confidence})")
# execute_tool lookup_formulary -> SpanType.TOOL_CALL (confidence: high)
Spans are classified against the OTEL GenAI semantic conventions (gen_ai.operation.name, gen_ai.tool.name, gen_ai.request.model, ...) into: TOOL_CALL, MODEL_CALL, RETRIEVAL, AGENT_INVOCATION, EVENT_LOOP, HUMAN_REVIEW, or CUSTOM — each with a confidence score and the reason for the classification.
Traces are fingerprinted to the framework that produced them — Strands Agents, LangChain/LangGraph, PydanticAI, Claude Agent SDK — so downstream tools can handle framework-specific quirks (e.g., where message content lives) without their own detection logic.
Classification rules live in a SemanticConventionRegistry. New frameworks, operation names, or attribute conventions are added as registry entries, not code changes:
from agentic_otel import SemanticConventionRegistry
registry = SemanticConventionRegistry()
registry.register_tool_op("my_framework.tool_exec")
result = registry.classify(span)
framework = registry.detect_framework(raw_trace_json)
For tools that want a fully structured representation, OTELNormalizer produces a NormalizedTrace — typed NormalizedSpan entries with token usage, data source references, resolved parent/child relationships, and extracted input/output text — from a single parsing pass:
from agentic_otel import OTELNormalizer
trace = OTELNormalizer().normalize(raw_trace_json)
Handles, without configuration:
resourceSpans exports and flat {"spans": [...]} dumps[{"key": ..., "value": {"stringValue": ...}}]) and flat dictscamelCase and snake_case span field names (traceId / trace_id)This is a community open source project, not an AWS service or product.
Development Status :: 4 - Beta classifier. The API may change between minor versions; pin a version if you depend on it.You are responsible for evaluating whether it fits your own compliance and operational requirements before relying on it.
Apache-2.0
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.0 | 31 Aug 2026 | 1 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 22:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:0bf56d17b44378fb2ff7415126d51fdd0ad357427be6a06fad2fb771be6cfeff