Skip to content
XLinkedIn
Sign Up →

Python SDK

The Kelet Python SDK instruments your agent code to send traces and signals. It wraps LLM calls with OpenTelemetry-compatible spans, handles session context automatically, and exposes a signal() API for capturing user feedback. A single kelet.configure() call at startup is all most frameworks need.

pip install kelet  |  Requires Python ≥3.10

Terminal window
pip install kelet

Two keys — never mix them:

  • Secret key (sk_...): server-only. Use this in kelet.configure(). Never expose it in frontend code.
  • Publishable key (pk_...): frontend-safe, for the React SDK only. Cannot send traces.

Get both from Settings → API Keys in the console.

Call once at startup, before any agent code runs.

import kelet
kelet.configure(
api_key="...", # or set KELET_API_KEY env var
project="my-agent", # optional; can override per session
)
ParameterTypeDescription
api_keystrAPI key. Defaults to KELET_API_KEY env var
projectstrProject name. Defaults to KELET_PROJECT env var
base_urlstrAPI URL. Defaults to KELET_API_URL env var
auto_instrumentboolAuto-instrument detected frameworks. Default True

Groups all LLM calls and tool uses that belong to one unit of work. Required when you own the orchestration loop. Skip for pydantic-ai, LangChain, or LangGraph — they set sessions automatically.

Works as both a context manager and a decorator (sync and async).

Context manager:

async with kelet.agentic_session(session_id="abc123", user_id="user-1"):
result = await agent.run(...)

Decorator:

@kelet.agentic_session(session_id="abc123")
async def handle_request():
return await agent.run(...)
ParameterTypeDescription
session_idstrRequired. Unique ID for this unit of work
user_idstrOptional. Associates the session with a user
projectstrOptional. Overrides the project set in configure()

Streaming: wrap the entire generator body, including the final sentinel. Trailing spans are silently lost if the session exits before the stream finishes.

async def stream_response(session_id: str):
async with kelet.agentic_session(session_id=session_id):
async for chunk in llm.stream(...):
yield chunk

Names an agent within a session for multi-agent attribution. Use when multiple agents run in one session, or when your framework doesn’t expose agent names (pydantic-ai does; raw OpenAI/Anthropic SDK calls don’t).

with kelet.agent(name="retriever"):
docs = await fetch_docs(query)

Sends a signal. Must be awaited. Call inside agentic_session() — session ID resolves from context automatically.

await kelet.signal(
kind=kelet.SignalKind.FEEDBACK,
source=kelet.SignalSource.HUMAN,
trigger_name="user-vote",
score=1.0,
)
ParameterTypeDescription
kindSignalKindFEEDBACK or EDIT
sourceSignalSourceHUMAN or SYNTHETIC
trigger_namestrUse source-action format: user-vote, user-edit
scorefloat0.0–1.0. For votes: 1.0 = positive, 0.0 = negative
valuestrOptional text: feedback content, diff, reasoning
session_idstrOptional. Resolved from context if omitted
kelet.get_session_id() # current session ID
kelet.get_trace_id() # current trace ID
kelet.get_user_id() # current user ID

Returns None if called outside agentic_session().

If you use Logfire, Kelet attaches its processor to Logfire’s existing TracerProvider automatically:

import logfire
import kelet
logfire.configure(...)
kelet.configure() # attaches to Logfire's provider

Or create the processor explicitly:

processor = kelet.create_kelet_processor()
logfire.configure(additional_span_processors=[processor])
VariableDescription
KELET_API_KEYAPI key (required if not passed to configure())
KELET_PROJECTDefault project name
KELET_API_URLAPI base URL