Send your AI agent's OpenTelemetry traces to Pelennor.
Project description
pelennor
Send your AI agent's OpenTelemetry traces to Pelennor, where they become conversations you can read, search, and turn into evals.
pip install "pelennor[langchain]"
import pelennor
pelennor.init(api_key="plk_...") # the key from your agent's Lens page
with pelennor.conversation(id=thread_id, user="cust_123"):
agent.invoke({"messages": [("user", message)]})
That's the integration. Every model call, tool call and span your agent produces
inside the conversation block is exported and stitched into one conversation
keyed by id.
init() reads PELENNOR_API_KEY from the environment when you don't pass it, so
nothing but the key need live in code.
Documentation
| LangChain & LangGraph | Full setup for the stack most people are on. Start here. |
| Conversations | How turns get stitched, and what to use as an id. |
| Privacy and content capture | Exactly what leaves your process, and how to send less. |
| Manual instrumentation | For a framework nothing instruments. |
| Reference | Every argument, every environment variable. |
| Troubleshooting | "I see no traces." Start at the top. |
How it works
We don't write your spans. Your framework already emits them through an
instrumentor — a library that hooks its callbacks. init() switches on
whichever ones you have installed and gets out of the way. An instrumentor sees
the model's real message list, real token counts and real exceptions;
hand-written spans can only approximate all three.
We add the one thing OpenTelemetry lacks: a conversation. OTel's largest
unit is a trace, which is one request — turn 2 of a chat arrives as a completely
unrelated trace. pelennor.conversation(id=...) stamps a shared
gen_ai.conversation.id on every span started inside it, so the turns join back
up. It's a ContextVar, so it follows your code across await points and into
worker threads, which is where agent frameworks do their work.
We export a copy, we don't take over. If your process already has a
TracerProvider, we attach to it — your exporters keep working and a copy comes
to us. We never replace it; OpenTelemetry's global provider is set-once, so
replacing it would silently do nothing.
Auto-instrumentation
pip install "pelennor[langchain]" # LangChain and LangGraph
pip install "pelennor[openai]" # OpenAI
pip install "pelennor[anthropic]" # Anthropic
pip install "pelennor[llama-index]" # LlamaIndex
The core install is deliberately thin — the OTel SDK and an OTLP/HTTP exporter —
so it isn't tied to one instrumentation vendor. init() activates whichever
instrumentors are present, whether they came from an extra or from your own
dependencies.
Options
pelennor.init(
api_key="plk_...",
endpoint="https://self-hosted", # or PELENNOR_ENDPOINT; defaults to the cloud
service_name="support-bot", # shows up on your traces
capture_content=False, # send metadata only, never message text
instrument=True, # auto-activate installed instrumentors
)
capture_content=False sets every content switch the installed instrumentors
offer, before any of them start, so message text is never put on a span in the
first place — nothing is stripped later in the pipeline. Model names, token
counts, tool identity, timings and errors still come through. Two things it does
not cover: retrieved documents (no instrumentor offers a switch for RAG
passage text) and spans you write yourself. The
privacy guide
has the full list.
Every variable is applied with setdefault, so anything already set in your
environment wins over ours.
You don't need this SDK
Pelennor's ingest speaks OTLP/HTTP and reads eight tracing dialects —
OpenTelemetry GenAI (current, event-era and legacy), OpenInference,
OpenLLMetry, Traceloop, Langfuse and the Vercel AI SDK. Point an exporter you
already run at https://api.pelennor.ai/ingest/v1/traces with an
Authorization: Bearer header and set a conversation id yourself.
The SDK exists to make the common case one line, not to be a toll gate.
It will never break your agent
init() never raises. A missing key, an unreachable endpoint or a broken
instrumentor each degrade to "no telemetry" and a log line, never an exception in
your request path. Telemetry is not allowed to take down the thing it observes.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pelennor-0.1.2.tar.gz.
File metadata
- Download URL: pelennor-0.1.2.tar.gz
- Upload date:
- Size: 25.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3b6cfa671f23de1380c2e4c37cd3b8a6b2b58fc3f7d002f4a87e31741b85d2d
|
|
| MD5 |
31095ed5aad5c6a2e05ce9a9d089ca86
|
|
| BLAKE2b-256 |
6a2461ee1ecc59d271e52af28d859824c1f1ca7fd0d1f08106a01abf6bd3e509
|
File details
Details for the file pelennor-0.1.2-py3-none-any.whl.
File metadata
- Download URL: pelennor-0.1.2-py3-none-any.whl
- Upload date:
- Size: 13.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1334cdb95c0f2f7e61eb363c7d4f06b13b5c7dc02d0b6d8563d94b44d83a5c44
|
|
| MD5 |
9089f9ba2cef728393a316e33b863187
|
|
| BLAKE2b-256 |
4a66214f1dac0cca130eb76af7d6376bec96668a739f8495d2b3a679115cd3db
|