Search

↑↓ to move↵ to openesc to closetop 6 documentation results

Book a demoTry TokenTriage

In development · Explore the product preview. Join the launch list or book a walkthrough.

Browse docs

Python SDK

The complete Python surface — every exported name, its signature, and where the behaviour is documented in full.

ReferenceLast updated

On this page

The complete public surface of tokentriage for Python, in one place. Behaviour is documented on the topic pages; this is the list of what exists and what each call takes.

import tokentriage as tt

Requires Python 3.10 or newer. Local unreleased version 1.0.0rc2, contract version 1, zero runtime dependencies.

Configured provider client

The unreleased tokentriage.client.TokenTriage accepts base_url, api_key and mode="managed" | "self_hosted". It reads TOKENTRIAGE_BASE_URL and TOKENTRIAGE_API_KEY when arguments are omitted.

Use openai() or async_openai() to construct official provider clients. openai_options() and async_openai_options() support your own constructor and borrowed HTTP transport. metadata(response) and error_details(error) read information tied to that response or error.

Those four, plus native() and async_native(), take the saved-mode binding: gateway_id (required), environment_id, base_url, credential_source and provider_api_key. Supplying gateway_id selects saved mode, where api_key becomes the Authorization bearer and the gateway and environment selector headers are stamped for you; send the literal "gateway" as the model. provider_api_key needs credential_source="request_supplied", and a provider key passed without it raises ConfigurationError naming provider_key_not_allowed before a request is built.

Start with a routed request and async and streaming examples.

Guardrail refusals

A gateway that refuses a request on a guardrail answers 403 for a policy block and 503 for a guard whose detector could not run, with the typed refusal at the top level of the body and x-tt-guardrail: blocked | unavailable on the response. The SDK-owned transport raises it as its own exception rather than handing back a response the provider client would read as an empty error.

GuardrailRefusal (from tokentriage.client), raised by openai(), async_openai() and native() clients:

from tokentriage.client import GuardrailRefusal

try:
    client.chat.completions.create(model="gateway", messages=messages)
except GuardrailRefusal as refusal:
    print(refusal.type, refusal.binding, refusal.category, refusal.phase, refusal)

Every failure that is not a guardrail refusal keeps its own provider class and propagates, so a broken route cannot be mistaken for refused content.

Attribute What it says
type "guardrail_blocked" or "guardrail_unavailable"; None mid-stream
binding the guardrail binding that acted
category pii, secrets, injection, … when the refusal reached one
phase input, output or stream
rule_ref the policy rule that fired — a block only
reason which detector was suspended — an unavailable refusal only
status 403 or 503; None mid-stream
disclosure the x-tt-guardrail value, when the response carried it
mid_stream the refusal was read from stream bytes, not from a response
response the raw response, for the safe routing headers; None mid-stream

rule_ref and reason are never both set, and neither is ever filled in for the other: a block means “do not retry this content”, an unavailable guard means “retry”. refusal.blocked and refusal.unavailable are the two predicates, and str(refusal) is a sentence naming what acted. It carries no credential, no header value and no request content.

guardrail_refusal(error) narrows any exception to a GuardrailRefusal or None, including one raised by a borrowed transport this SDK did not wrap. stream_guardrail_refusal(data) reads a mid-stream refusal out of relayed SSE bytes: that case is not an error at all, just a terminal delta carrying finish_reason: "content_filter" (exported as STREAM_FINISH_REASON) and no explanation, because a refusal that said why would be an oracle for the detector that fired. The full disclosure is on the request’s row, never on the wire.

TypeScript cannot raise its own class here and narrows instead; see parity.

Configuration

init(base_url=None, disabled=None, log=None, emit_traceparent=False, tier_header=None, admin_url=None, exporters=(), *, agent=None, user=None, tenant=None, feature=None, tags=None)

Installs the process configuration. Resolution is argument, then environment, then default. Invalid instrumentation configuration raises TokenTriageConfigError. The five keyword-only dimension arguments form the lowest precedence layer.

check(admin_url=None, *, probe=True) → CheckReport

The first-run doctor. Lints configuration and probes the admin plane only, not the data plane. Prints its report and returns it. See install and configure.

Scopes

trace(agent=None, user=None, tenant=None, feature=None, tags=None, trace_id=None)

step(agent=None, step_class=None, user=None, tenant=None, feature=None, tags=None, parent=None, step_id=None)

Both are context managers and decorators. step_class must be user_turn, tool_loop or provider_state. parent accepts a step id or a Step, and is the only identity override.

observe(agent=None, step_class=None, user=None, tenant=None, feature=None, tags=None, parent=None)

Decorator sugar over step. No TypeScript equivalent.

current_step() → Step | None

The innermost open explicit step, not an adapter’s implicit one.

Behaviour: traces, steps, and context.

Wire

headers(**overrides) → dict[str, str]

The resolved x-tt-* map. Override keys are agent, tier, cache, user, tenant, feature and tags; tier and cache are accepted here only. Overrides are ephemeral. Returns {} when disabled.

receipt(source, status=None) → Receipt

Parses a response, an error response, or a plain header mapping. Never raises. Returns an all-absent receipt rather than None on any failure.

last_receipt() → Receipt | None

The most recent receipt on the nearest open scope, step before trace. Outside any scope, None plus TT-SDK-013.

Behaviour: from your call to the wire and reading the receipt.

Adapters

Call Wraps
httpx_client(*, origins=None, base_url=None, **kwargs) a new httpx.Client
async_httpx_client(...) a new httpx.AsyncClient
instrument_httpx(client, ...) an existing httpx client, in place
instrument_requests(session, ...) a requests session
from tokentriage.adapters.langchain import TTCallbackHandler LangChain / LangGraph runs
from tokentriage.adapters.crewai import instrument_crew a CrewAI crew
from tokentriage.adapters import otel → otel.bridge() OpenTelemetry span ids

Each needs its extra installed. Importing one patches nothing.

Behaviour: adapters.

Ledger

from tokentriage import ledger

All synchronous. All use the credential-containment protocol and read the token from TOKENTRIAGE_ADMIN_TOKEN only.

ledger.fetch(receipt_or_req_id, admin_url=None, wait_s=0.0) → RowView

ledger.fetch_trace(receipt_or_trace_id, admin_url=None, wait_s=0.0) → TraceView

ledger.feedback(receipt_or_req_id, ok, note=None, admin_url=None) → FeedbackAck

ledger.outcomes(receipt_or_req_id, metrics, source, evaluator, eval_ver, labels=None, admin_url=None, basis=...) → OutcomeAck

metrics is a non-empty sequence of {"metric": str, "value": float, "pass": bool} mappings, where value is required and pass is optional. basis is accepted and never sent.

Errors: PlaneCollision, AdminAuthRequired, NotFound, LedgerError. feedback is the one call that is not shielded and raises on failure.

Behaviour: fetching a costed row and outcomes and feedback.

Types

Receipt, Cost, Rewrite, CacheInfo, Refusal, Trace, Step, StepRecord, Exporter, TokenTriageConfigError, plus CheckReport and CheckFinding.

All receipt types are immutable. Cost has no public constructor.

Receipt carries request_id, mode, decision, model_rewrite, cache, refusal, cost, extra and status_code, plus the cost_display property and dashboard_url(admin_url=None).

Exporter

register_exporter(exporter) installs an object with on_step_end(record). Survives a later init().

DebugExporter() prints one line per closed step, locally, with no network:

[tt] step trace=b2728443b6c6bfb8b6029a4bcb24debe step=66fcd77192c62295 parent=None agent=planner class=user_turn status=ok dur_us=5.0 receipts=0

An exporter that raises cannot break a scope. The default registry is empty.

Testing

from tokentriage.testing import RecordingTransport, assert_tt_headers

Needs httpx. See testing instrumented code.

Management

from tokentriage.management import Client

A separate, generated client for the admin API, on its own contract version. Not re-exported from the package root. See the management client.

What is imported when

Importing tokentriage binds the scopes, the wire calls, the types and the exporter. Everything else resolves on first use: ledger, check, testing and the adapters.

That is why import tokentriage opens no socket. The module that can open one is not imported until you call something that needs it, which also means an uninstalled extra surfaces its error at first use with a message naming what to install, rather than at import.