Metadata-Version: 2.4
Name: tokli
Version: 0.0.0
Summary: Report-only usage tracking for OpenAI, Anthropic, Gemini, DeepSeek, xAI, Mistral, Qwen, GLM, Kimi and OpenRouter — wrap your client, we read the tokens.
Project-URL: Homepage, https://tokli.dev
Project-URL: Source, https://github.com/joagarc2/tokli-v2
Project-URL: Issues, https://github.com/joagarc2/tokli-v2/issues
Author-email: tokli <hello@tokli.dev>
License-Expression: MIT
License-File: LICENSE
Keywords: anthropic,cost,deepseek,gemini,glm,kimi,llm,mistral,openai,openrouter,qwen,tokli,usage,xai
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.27.0; extra == 'anthropic'
Provides-Extra: dev
Requires-Dist: mypy>=1.14; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.25; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Provides-Extra: gemini
Requires-Dist: google-genai>=1.0.0; extra == 'gemini'
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == 'openai'
Description-Content-Type: text/markdown

# tokli

Report-only usage tracking for [tokli](https://tokli.dev) — a cost & usage dashboard for AI
APIs. Wrap your existing provider client, keep calling it exactly as before, and tokli reports
the token usage in the background. **We never see your provider API key** and we never sit in
your request's critical path.

Supports OpenAI, Anthropic, Gemini, DeepSeek, xAI, Mistral, Qwen, GLM, Kimi and OpenRouter.

> **`0.0.0` is a placeholder release reserving the name.** The wrappers land in `0.1.0`.

## Install

```bash
pip install tokli
```

`openai`, `anthropic` and `google-genai` are optional extras — tokli has **zero runtime
dependencies** and never pulls a provider SDK into your app.

## Quickstart

```python
from openai import OpenAI
from tokli import wrap_openai

client = wrap_openai(OpenAI())  # ingest key from TOKLI_INGEST_KEY
client.chat.completions.create(model="gpt-5.4", messages=messages)
```

The returned client behaves exactly like the original: every attribute we don't instrument
passes straight through, and `isinstance(client, OpenAI)` still holds. `AsyncOpenAI` works
through the same `wrap_openai` — there is no separate async wrapper.

Without an ingest key (neither the `ingest_key` argument nor `TOKLI_INGEST_KEY`), the wrapper
is a **silent no-op**: your app keeps working exactly as before, nothing is reported.

## Config

| Argument | Env var | Default | Notes |
| --- | --- | --- | --- |
| `ingest_key` | `TOKLI_INGEST_KEY` | — | Required. Without it, the wrapper is a no-op. |
| `endpoint` | `TOKLI_ENDPOINT` | `https://api.tokli.dev` | Ingest API base URL. |
| `timeout_ms` | `TOKLI_TIMEOUT_MS` | `2000` | Timeout for the fire-and-forget report request. |
| `flush_ms` | `TOKLI_FLUSH_MS` | `2000` | How long to wait at exit for pending reports; `0` disables. |
| `on_error` | — | no-op | Called if reporting fails; never raises into your code. |

## How it works

Your code keeps calling the provider with your own key. After the response comes back, the SDK
reads the `usage` object already present in it and sends those raw numbers to tokli,
fire-and-forget — it never blocks your request, your event loop, or your key. Cost is computed
server-side against a versioned price table, not by the SDK.

Reporting can never break your app: if anything in our own path raises — including your
`on_error` handler — you still get the provider's response untouched.

## Links

- [tokli.dev](https://tokli.dev)
- [Source & issues](https://github.com/joagarc2/tokli-v2)
