OpenToken Python SDK
Project description
Open Token Python SDK
Using UsageReporter directly
If you want to report usage from any provider, use UsageReporter directly:
from opentoken import UsageReporter
reporter = UsageReporter(
open_token_api_key=os.environ["OPENTOKEN_API_KEY"],
tags={"service": "checkout-api", "env": "prod"},
batch=True, # default; set False to POST one event at a time
)
response = your_provider_client.chat.completions.create(...)
reporter.report_usage(response=response, latency_ms=..., tags={"workflow_id": "..."})
report_usage(...) enqueues the report on a bounded in-memory queue and
returns immediately (~microseconds on the caller's thread). A background
daemon thread drains the queue and POSTs to /v1/usage:batch. You don't
manage the thread — it's started lazily on your first call and dies with
the process.
OpenAI Agents SDK integration
If you're using the OpenAI Agents SDK, register the tracing bridge once at
startup and every Runner.run(...) will forward its LLM spans to
OpenToken. You never call report_usage yourself.
from opentoken import UsageReporter, with_tags
from opentoken.integrations.agents import register_trace
from agents import Agent, Runner
# One-time setup — static tags apply to every event this reporter sends.
reporter = UsageReporter(open_token_api_key=..., tags={"env": "prod"})
register_trace(reporter)
sales_agent = Agent(name="sales_agent", model="gpt-5.5", instructions="...")
# Per-request handler — dynamic tags scoped to this one call.
async def handle(customer_id, question):
with with_tags(customer_id=customer_id, agent_name="sales"):
return await Runner.run(sales_agent, question)
Every event that flows out of that Runner.run lands with the merged tag
set — reporter defaults + whatever's active in the surrounding with_tags
block.
with_tags(**tags) — dynamic per-request tags
with_tags is the customer-facing knob for tags that vary per request:
customer_id, session_id, workflow, whatever you want. It's a
context manager backed by contextvars, so:
- Async-safe. Concurrent tasks each maintain their own tag scope — no cross-request bleed.
- Nested. Inner blocks inherit outer tags and override on collisions.
- Works with both flows. Whether the event is emitted by the Agents
integration or by a manual
reporter.report_usage(...)call, the same ambient stack is read.
Tag precedence (highest wins)
For any event, tags merge in this order:
UsageReporter(tags=...)— reporter defaults, static, process-widewith_tags(...)— ambient, request-scopedreport_usage(tags=...)— per-call, most specific
Later layers override earlier ones on key collisions.
What lands in transactions.tags
Given the example above, one event would look like:
{
"env": "prod", // reporter default
"customer_id": "cus_123", // from with_tags
"agent_name": "sales" // from with_tags
}
No auto-injected tags. What you write is what lands.
Failure modes
- HTTP failure (5xx, timeout, network blip). The batch is retried up to 3 times with exponential backoff + jitter, then dropped and logged. The worker keeps running.
- Unexpected exception in the worker. The worker's main loop catches
any exception, logs it, and continues. If the thread does die despite
that, the next
report_usage()call starts a fresh one; only the event in-flight at the time of the crash is lost — queued events are preserved. - Process death (SIGKILL, crash, sudden exit). The in-memory queue is
lost. Long-lived servers are fine; short scripts should call
reporter.flush()before exit, or rely on the built-inatexitflush (bounded to 5 seconds so slow OpenToken never hangs your process).
Enable logging.getLogger("opentoken") to see retries, drops, and worker
restarts. Call reporter.stats() any time to inspect sent, dropped,
retried, batches_flushed, worker_restarts, queue_depth.
Response shape
Both /v1/usage and /v1/usage:batch return the same positional bool
array — one element per input event:
{"results": [true, false, true]}
Each true means the event was accepted; each false means it failed
(unknown model, missing usage block, etc.). The SDK counts true events
toward sent and retries false events up to max_retries times, then
counts still-failing events toward dropped.
HTTP status is 200 for any well-formed request — individual event
failures are surfaced inside results, not at the HTTP layer. The
endpoints return 4xx only for whole-request problems (auth, malformed
JSON, oversized batch).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opentoken_sdk-0.1.0.tar.gz.
File metadata
- Download URL: opentoken_sdk-0.1.0.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b1c3edb370a400f13d57e0a1223c593d201c4084ed0f7e9d8bee035429442ae
|
|
| MD5 |
42922a9298dfd1913f660d7f4d44d233
|
|
| BLAKE2b-256 |
a124d27c0bbb112cc3955243ca666c16c855ad7eb62b79e0c9ad63a8db70364f
|
File details
Details for the file opentoken_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: opentoken_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
058f5b1b12cf9ffbe5ea56e9682b24a1310acee0678009b3d034ace089839c71
|
|
| MD5 |
374dbc6ca7521043f7f1bb6f38b2ba33
|
|
| BLAKE2b-256 |
c00ab128df6b6a836c95c40138d786b3a20274a09af2c39ea65a5413d0459d57
|