Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pelennor-0.1.2.tar.gz (25.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pelennor-0.1.2-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

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

Hashes for pelennor-0.1.2.tar.gz
Algorithm Hash digest
SHA256 e3b6cfa671f23de1380c2e4c37cd3b8a6b2b58fc3f7d002f4a87e31741b85d2d
MD5 31095ed5aad5c6a2e05ce9a9d089ca86
BLAKE2b-256 6a2461ee1ecc59d271e52af28d859824c1f1ca7fd0d1f08106a01abf6bd3e509

See more details on using hashes here.

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

Hashes for pelennor-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1334cdb95c0f2f7e61eb363c7d4f06b13b5c7dc02d0b6d8563d94b44d83a5c44
MD5 9089f9ba2cef728393a316e33b863187
BLAKE2b-256 4a66214f1dac0cca130eb76af7d6376bec96668a739f8495d2b3a679115cd3db

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page