Skip to main content

tellproof (Python SDK)

One line to send evidence telemetry from an AI product to the local Tellproof evidence agent.

pip install tellproof
import tellproof
tellproof.init()

The SDK records one span per model call with provider, model, region, token counts, operation, timing and error status, and sends it as OTLP JSON to the agent on http://127.0.0.1:4318 (or TELLPROOF_AGENT_URL). The agent aggregates per hour and signs the aggregates: it keeps them in a local evidence log (tellproof-agent local) or sends them to Tellproof (tellproof-agent connect). The SDK never reads prompts, completions, function arguments, return values or exception messages, so there is no content to filter.

  • No dependencies: standard library only, Python 3.10+.
  • Never slows or breaks the app: spans go to a bounded background buffer; when it is full, spans are dropped and counted (tellproof.stats()). SDK errors are swallowed and counted.
  • TELLPROOF_DISABLED=1 turns it off. init() is safe to call more than once.
  • Proxies are never used: the agent is local.
  • Works across threads, asyncio tasks and forked workers (gunicorn, uWSGI).

Automatic instrumentation

init() instruments the client libraries that are installed. Nothing to configure:

Library Calls
openai chat.completions.create / parse / stream, responses.create / parse / stream, embeddings.create, completions.create; sync, async, streaming. Azure OpenAI is reported as azure.ai.openai; other OpenAI-compatible endpoints by their host name.
anthropic messages.create and messages.stream (and beta.messages); sync, async, streaming. AnthropicBedrock and AnthropicVertex are reported as aws.bedrock and gcp.vertex_ai with their region.
boto3 (Bedrock Runtime) converse, converse_stream, invoke_model, invoke_model_with_response_stream

Per call it reads the request's model and stream flag, and from the response only the model, the usage block, the stop reason and Bedrock's token-count headers. Input tokens follow what the provider bills (Anthropic: uncached + cache writes + cache reads; Bedrock: inputTokens, as CloudWatch counts them), so Tellproof can reconcile traced against billed tokens.

Things to know:

  • Streams are recorded when they end, are closed, or leave a with block, once, with the usage they reported. A stream dropped half-read is recorded on the next call or flush.
  • OpenAI streamed chat completions report usage only if asked. tellproof.init(stream_usage=True) sets stream_options={"include_usage": True} when the app has not set it; the stream then ends with one extra chunk with no choices. Off by default, so the app's streams are unchanged.
  • Bedrock guardrails: a Converse call with guardrailConfig is a guarded call, block when the stop reason is guardrail_intervened, else allow.
  • invoke_model_with_response_stream reports its token counts only inside the streamed body, which the SDK never reads, so those calls are counted without tokens. with_raw_response calls are counted without tokens too.
  • tellproof.init(instrument=False) turns automatic instrumentation off; the helpers still work.

What the helpers record

Tellproof's evidence objectives need a few facts that no LLM client knows. Each helper is a context manager (with or async with) and a decorator.

Helper Records
tellproof.prompt(name, version) the prompt (name and version, never its text) used by calls inside
tellproof.personal_data(redacted=False) spans inside handle personal data; redacted says it was removed or masked before the model saw it
tellproof.guardrail(decision=None) the guardrail decision (allow, block, flag) for calls inside; set it later with g.allow(), g.block(), g.flag()
tellproof.tool(name, high_impact=False, approved=False) a tool call; failures inside mark it failed; set t.approved = True once approved
tellproof.agent_run(name) one agent run; model changes are tracked per agent
tellproof.escalation() the request was handed to a person
tellproof.trace() groups everything inside into one trace (for example one web request)
tellproof.llm_call(provider, model, operation="chat", region=None) a model call the SDK does not instrument; report usage with c.usage(input_tokens, output_tokens)
with tellproof.trace(), tellproof.prompt("claims-triage", "14"), tellproof.personal_data(redacted=True):
    with tellproof.guardrail() as g:
        if not input_policy_ok(request):
            g.block()          # recorded as one blocked call; the model was never called
            return refusal()
        with tellproof.llm_call("openai", "gpt-4.1-mini", region="us-east-1") as c:
            r = client.chat.completions.create(...)
            c.usage(r.usage.prompt_tokens, r.usage.completion_tokens)
        g.flag() if needs_review(r) else g.allow()

@tellproof.tool("issue_refund", high_impact=True)
def issue_refund(claim): ...

Names and versions are capped at 128 characters; anything that is not a string or an integer is ignored.

Calls inside a guardrail scope are held until the scope ends, so a decision made after the call (an output check) still applies. A block with no call inside counts as one blocked call; pass provider= and model= to attribute it.

Guardrail canaries

Show that your guardrail catches something, not only that it ran. The SDK passes synthetic, known-bad probes (prompt injection, jailbreak, made-up personal data, a documented example AWS key) to your own guardrail check and records only the kind and whether it was caught (EO-CAN-01):

tellproof.schedule_canaries(lambda text: my_guardrail.scan(text).blocked, every=3600)  # now, then hourly
tellproof.run_canaries(check)          # once: {"prompt_injection": True, ...}; arun_canaries for an async check
tellproof.canary("toxicity", True)     # a canary you run with your own probe

The check returns True, "block" or "flag" when it would stop the text; anything else, or an exception, counts as missed. Pass probes to the guardrail only, never to the model. The probes never leave the process (tellproof.PROBES); with the SDK off the check is never called.

Already on OpenTelemetry?

You can skip the SDK: point an OTLP/HTTP JSON exporter at the agent (http://127.0.0.1:4318/v1/traces) and set the tellproof.* attributes yourself (spec/semconv-map.json). Do not run both for the same calls, or they are counted twice.

Development

python3 -m unittest discover -s sdk/python/tests
python3 sdk/python/tests/scenario.py   # rewrite sdk/testdata/python-export.jsonl

Metadata

Release files for tellproof 0.2.0

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

Source distribution (sdist)

Source distribution for tellproof 0.2.0
File Size Uploaded
tellproof-0.2.0.tar.gz 35.2 kB Details

Built distribution (wheel)

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

Total release size: 61.4 kB

Release files / tellproof-0.2.0.tar.gz

Download URL tellproof-0.2.0.tar.gz
Size 35.2 kB
Tags Source
SHA-256 checksum
How to use checksums
cf5dd985cbdeb969c17d14afddba42eb775baeabc87a4cc7819357a1e80e6ded
BLAKE2b-256 checksum
How to use checksums
d5f787456ec97749effe17e65136f0853a16b802f5e131f3eaec4a9b10e9e5e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 17, 2026.

Transparency log

Release files / tellproof-0.2.0-py3-none-any.whl

Download URL tellproof-0.2.0-py3-none-any.whl
Size 26.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c4eb254ecc24823db1c655dac578db4581f571771e10ba095cc941d7cac0fb82
BLAKE2b-256 checksum
How to use checksums
4d3424e9099fb560c316af520b30e94c051eb972e9c90558d27f30b93eec7438
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

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