OpenTelemetry
The OpenTelemetry integration is the import-free path. If your
team already runs an OTel collector for distributed tracing,
point its OTLP/HTTP exporter at Adjudon and every span carrying
the gen_ai.* semantic-convention attributes flows into the
Decision Trace pipeline as if you had
called the SDK directly. No import adjudon, no constructor,
no per-call wrapper. The collector you already operate becomes
the integration.
Endpoint
POST https://api.adjudon.com/otel/v1/traces
OTLP/HTTP JSON only today. The endpoint accepts payloads up to
5 MB — OTLP batches commonly carry 1,000+ spans, and the
ceiling exists to absorb the largest production batches without
splitting them. Authentication is the same adj_agent_* API key
the Traces API accepts; the same
per-agent and per-org rate limits apply.
Configure your OTel SDK
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
provider = TracerProvider(resource=Resource.create({
"service.name": "customer-support-bot", # → DecisionTrace.agentId
}))
exporter = OTLPSpanExporter(
endpoint="https://api.adjudon.com/otel/v1/traces",
headers={"Authorization": "Bearer adj_agent_..."},
)
provider.add_span_processor(BatchSpanProcessor(exporter))
exporters:
otlphttp/adjudon:
endpoint: https://api.adjudon.com/otel
traces_endpoint: https://api.adjudon.com/otel/v1/traces
headers:
authorization: Bearer adj_agent_...
encoding: json
service:
pipelines:
traces:
exporters: [otlphttp/adjudon]
The collector route is the production deployment pattern: route every gen-AI service through one collector, attach Adjudon as one of several exporters (alongside Tempo / Jaeger / your incumbent APM), and let the collector handle batching and retry.
Attribute mapping
The Adjudon mapper consumes the
OTel GenAI semantic conventions
and maps them onto the DecisionTrace schema:
| OTel attribute | DecisionTrace field |
|---|---|
service.name (resource) | agentId |
gen_ai.system | metadata.llm_provider |
gen_ai.request.model | metadata.request_model |
gen_ai.response.model | metadata.response_model |
gen_ai.request.temperature | inputContext.temperature |
gen_ai.request.max_tokens | inputContext.max_tokens |
gen_ai.request.top_p | inputContext.top_p |
gen_ai.response.finish_reasons | outputDecision.finish_reasons |
gen_ai.usage.input_tokens | metadata.tokens_input |
gen_ai.usage.output_tokens | metadata.tokens_output |
event gen_ai.content.prompt | inputContext.prompt |
event gen_ai.content.completion | outputDecision.completion |
span name · gen_ai.operation.name | triggeringCondition |
A span without any gen_ai.* attribute is silently dropped
— OTel collectors mix gen-AI traffic with HTTP, DB, and
queue spans, and Adjudon only ingests the gen-AI subset. The
endpoint returns 200 OK even when every span in the batch was
dropped, per the OTLP spec.
Deduplication on retry
The mapper computes a deterministic traceId from the OTel
trace ID + span ID:
traceId = otel-<otel_trace_id>-<otel_span_id>
A retry that re-sends the same span produces the same traceId;
MongoDB's unique index on traceId accepts the duplicate as a
no-op (E11000 caught and treated as success). This is what
allows the OTel pipeline to skip the standard
Idempotency-Key middleware
— the dedup is intrinsic to the OTel identifiers.
Errors
The endpoint returns standard HTTP responses with the same error
shape as POST /traces. The most common failure modes:
| HTTP | Cause |
|---|---|
400 | Malformed OTLP JSON; collector should not retry |
401 | Missing or invalid adj_agent_* API key |
429 | Per-agent or per-org rate limit hit; collector should back off |
5xx | Adjudon transient; collector retries with exponential backoff |
Per OTLP, the server SHOULD return 200 OK for partial-success
batches; Adjudon does so and surfaces rejected counts in the
response body so the collector can log them.
Resources
- Quickstart — first trace in 60 seconds via the SDK path
- Traces API — the underlying resource OTel spans materialise as
- Authentication —
adj_agent_*key format and rotation - Python SDK — the
adjudon-oteladapter package for teams that want the import-driven path - OpenTelemetry GenAI conventions:
opentelemetry.io/docs/specs/semconv/gen-ai/ - Error Codes — the broader error taxonomy