Skip to main content

Telmoni Python SDK

telmoni: an agent's runs, steps, model calls and tool calls as OpenTelemetry spans, sent to Telmoni and nowhere else. It runs a tracer provider of its own beside whatever OpenTelemetry your application already has, sends nothing outside a run, and takes prompts, completions and tool payloads off every span before it leaves the process unless you ask and the project allows.

Installation

Python 3.10 or later:

pip install telmoni

The hosted service at https://api.telmoni.com, the SDK's default endpoint, is not open yet, nor are the docs at telmoni.com/docs. Until they are, run Telmoni yourself and point TELMONI_ENDPOINT at its machine host; the docs read in telmoni/docs.

Quick start

from telmoni import Bounds, Telmoni, Usage

# Reads TELMONI_ENDPOINT, TELMONI_API_KEY (a key with the ingest scope) and
# TELMONI_ORG, and nothing else.
telmoni = Telmoni.from_env()


@telmoni.run("support-bot")
def answer(question: str) -> str:
    with telmoni.step("plan"):
        with telmoni.model_call("gpt-4o-mini", provider="openai") as call:
            reply = ask_the_model(question)  # your provider's call
            call.answered(
                response_model=reply.model,
                usage=Usage(
                    input_tokens=reply.usage.input, output_tokens=reply.usage.output
                ),
            )
    with telmoni.tool_call("search"):
        results = search(reply.query)  # an exception marks the call failed
    return reply.text


with telmoni.run(
    "support-bot",
    user_id="user_42",
    session_id="conv_7",
    tags={"env": "prod"},
    bounds=Bounds(stall_after_s=60, max_steps=10, max_cost_usd=1.5),
) as run:
    ...

telmoni.flush()  # before the process exits, if it exits soon after a run

Each of run, step, model_call and tool_call is a context manager, an async with, and a decorator. An exception that escapes one marks the span failed with the exception's class, never its message, and is raised again; a KeyboardInterrupt or asyncio.CancelledError marks it cancelled. fail() and cancel() do the same by hand. run raises ValueError for a blank agent name or a sample rate outside (0, 1]. A bound or a token count is read from a number or its text, a stall's, steps' or count's fraction cut, and of what ingest would refuse, these are left off with one warning: a bound outside 1 to 4294967295, a cost not above 0, a token count below 0 or past 64 bits, a tag whose key is not 1 to 64 characters or whose value is past 256, and the tags past the first 32 kept, the most ingest keeps; an empty user, session, provider or response model is left off as unset. A name, model, provider, user, session, response model or error type that is no string goes as its text with one warning, as does a tag that is no string, finite number or bool; an exception or an exception's class handed to fail() goes as the class's name, never its message. Past ingest's caps, counted in characters, a name, the agent, a model, a provider, a response model or an error type is cut to its cap — a step's or a tool's name, and a model call's <operation> <model>, to 145, the rest to 128 — and a user past 128 or a session past 200 is left off, since cut it would name another; a step named nothing goes as step, and a model call with no model is named by its operation alone; each with one warning, where ingest would refuse the span, or the whole run for its agent, user or session.

A run recorded after it ended

A job that keeps its own log, or a hook that runs once the turn it reports is over, hands the finished run to record_run as data:

from datetime import datetime, timezone

from telmoni import ModelCallRecord, RunRecord, StepRecord, ToolCallRecord, Usage

telmoni.record_run(
    RunRecord(
        run_id="3d6f8a1c-5b2e-4f7a-9c0d-8e1f2a3b4c5d",  # yours, kept with the log
        agent="nightly-triage",
        session_id="conv_7",
        start=datetime(2026, 10, 12, 9, 0, tzinfo=timezone.utc),
        end=datetime(2026, 10, 12, 9, 0, 9, tzinfo=timezone.utc),
        inside=[
            ModelCallRecord(
                model="gpt-4o-mini",
                provider="openai",
                start=datetime(2026, 10, 12, 9, 0, 0, 100000, tzinfo=timezone.utc),
                end=datetime(2026, 10, 12, 9, 0, 2, tzinfo=timezone.utc),
                usage=Usage(input_tokens=1200, output_tokens=85),
            ),
            ToolCallRecord(
                name="search",
                start=datetime(2026, 10, 12, 9, 0, 2, tzinfo=timezone.utc),
                end=datetime(2026, 10, 12, 9, 0, 3, tzinfo=timezone.utc),
                error_type="TimeoutError",
            ),
        ],
    )
)
telmoni.flush()

It is sent as the live calls would have sent it, through the same exporter, content rules and sample rate, in a trace of its own named by the run's id, whatever trace is current. Each span's id is derived from the run's id and the span's place in the record, so the same record sent again is the same bytes, which ingest answers once: give a run the same id each time you send it. A record holds no content. A blank agent, a run id that is neither a hyphenated UUID nor 32 hex digits, or is the nil UUID, a time without its timezone or outside what ingest reads (after the Unix epoch, and less than 2^64 nanoseconds after it, in July 2554), an empty step's name or model, text longer than ingest keeps (a step's or a tool's name past 145 characters, the agent, a model, a provider, a user or an error type past 128, a session past 200, or a model call's operation and model past 144 together), or a span that ends before it starts raises ValueError. A field of the wrong type raises TypeError — a time that is no datetime, an item of another class, inside or calls that is no sequence (a list or a tuple, in the order it ran) — save a token count, read as a whole number where it can be and else left off with one warning, and an operation of None, a chat. Either sends nothing. A record the export queue has no room for raises QueueFullError, nothing of it queued: flush, or wait, and record it again.

Content

Prompts, completions, tool arguments and results (input_messages, output_messages, arguments, returned(...)) are recorded on the span and taken off by the exporter before anything leaves the process. They are sent only when the client is built with Config(capture_content=True) and the project's content mode, which the SDK learns from the server's first answer, is on.

Configuration

Config(endpoint, organization_id, api_key, capture_content, sample_rate, sampler, environment, release), or Config.from_env(), which reads TELMONI_ENDPOINT (default https://api.telmoni.com), TELMONI_API_KEY, TELMONI_ORG, TELMONI_ENVIRONMENT and TELMONI_RELEASE, a blank value counting as unset. environment and release name the deployment every span is sent from, as the resource's deployment.environment.name and service.version. sample_rate is the share of runs sent, dropped whole in the SDK's processor and never through the trace's sampled flag. The key never appears in repr, str or dataclasses.asdict, and pickle refuses it. It travels over HTTPS only: a plain-HTTP endpoint is refused with a ValueError unless its host is this machine — localhost, a name under it, 127.0.0.0/8 or ::1, an IPv4-mapped address read as its IPv4 — and no redirect is followed. A request to this machine goes through no proxy, whatever the environment names. An endpoint without a scheme gets https://, or http:// for this machine, as the CLI reads one; any other scheme is refused with a ValueError, as is one the four SDKs could read two ways: one not in printable ASCII, or holding credentials, an escape, a query, a fragment, a dot segment or a character a URL parser would escape, or a port of 0 or past 65535, or naming a host that is neither a name of letters, digits, dots, hyphens and underscores, in labels of 1 to 63 characters with no hyphen at either end and the last no number, nor an IPv4 address in four decimal parts, nor an IPv6 one in brackets.

A run across services

Before a request leaves a run, telmoni.inject(headers) writes the W3C traceparent of the span current and the run's id and agent as baggage members into any mutable mapping of headers. In the service that answers, run = telmoni.extract(request.headers) gives the run back, continued there: telmoni.step("work", run=run) and the calls inside nest under the caller's span and carry the caller's run, and nothing of the run itself is sent from this side. Headers that name no run give None, and a step opened with it is outside a run.

The variables, the attributes each span carries, and the other SDKs are documented at telmoni.com/docs/api/sdks.

Metadata

Release files for telmoni 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for telmoni 0.1.1
File Size Uploaded Provenance
telmoni-0.1.1.tar.gz 71.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for telmoni 0.1.1
File Interpreter ABI Platform
telmoni-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 114.8 kB

Release files / telmoni-0.1.1.tar.gz

Download URL telmoni-0.1.1.tar.gz
Size 71.1 kB
Tags Source
SHA-256 checksum
How to use checksums
8a6be771846c07143afd65d631346bdee200a5a3b869ff62b9d9dfc851278a5a
BLAKE2b-256 checksum
How to use checksums
a005d04f245f9e00246cc6a04e68662e0d41e039779805fd6aa5c3e904db72cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Release files / telmoni-0.1.1-py3-none-any.whl

Download URL telmoni-0.1.1-py3-none-any.whl
Size 43.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
617b04bdeb05609d7bcccf337b65e3afb7dc838d426593447b52c350cb4aefd7
BLAKE2b-256 checksum
How to use checksums
31c988440629f888ecbd2d84dddc5ceca3f80908a613d2b29bff9de6f81904a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Security for telmoni 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for telmoni-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page