TokenPolice
Docs
SDK reference

Supported versions

SDK 1.0.0: the runtimes it needs, what each provider and framework gives you, and the library versions we've verified it against.

Both SDKs are at 1.0.0, published as token-police.

PythonNode
RuntimePython 3.10+Node 20+ (ESM and CommonJS)
Installpip install token-policenpm i token-police
Importimport token_police as tpimport * as tp from "token-police"

The SDKs deliberately pin no provider library version. They detect the shape of whatever you have installed at runtime and fail open if it's something they don't recognise — so a provider release can't break your app, it can only cost you metering until we catch up. The one place that shows through today is Node + openai 7 (below).

Python

Everything in this table works on the base pip install token-police, except where an extra is named.

Provider / frameworkMeteredStreamingTool spansInstall
OpenAIautovia frameworkbase
Anthropicautovia frameworkbase
Amazon Bedrockautovia frameworkbase
Google Geminiautovia frameworkbase
Coherebase (chat and embeddings; no extra exists)
Mistralbase (chat, embeddings, OCR, transcription, FIM, speech on 2.x)
Together · Groq · Cerebras · OpenRouter · Hugging Face · LiteLLMbase
xAIbase — [xai] installs the xai-sdk client itself
Voyage AIn/a[voyageai] (embeddings)
LangChainauto[langchain]
LlamaIndexauto[llamaindex]
Pydantic AIauto[pydantic-ai]
OpenAI Agentsauto[openai-agents]
CrewAImanual[crewai]
Agnomanual[agno]

Extras: all, langchain, llamaindex, pydantic-ai, openai-agents, crewai, agno, xai, voyageai. (google also resolves, but it's an empty no-op kept for back-compat — Gemini is metered by the base install.)

pip install "token-police[all]" bundles the framework extras except CrewAI. CrewAI supports Python 3.10–3.13 but not 3.14 yet, so keeping it out of all is what lets [all] install everywhere; add it on its own line: pip install "token-police[crewai]".

Verified with

Python apps in our test fleet pin floors rather than exact versions, so most of these are "at least this" rather than "exactly this".

LibraryVerified
openaifloor ≥ 1.66.0
anthropic≥ 0.111.0, < 1
google-genai2.14.0
boto3 (Bedrock)floor ≥ 1.39.0
coherefloor ≥ 5.13.0 (5, 6 and 7 all work)
mistralai1.12.4 and 2.9.4 (both majors supported — see the note below)
langchain-core / -openai / -anthropic / -google-genai1.5.2 / 1.4.1 / 1.4.6 / 4.2.5
langgraph1.2.10
llama-index-core / -llms-openai / -llms-google-genai0.14.23 / 0.7.10 / 0.9.6
together / litellm / pydantic-ai / openai-agents / agno / voyageai / huggingface_hub / cerebras_cloud_sdk / xai-sdkfloors only (≥ 1.3.0 / ≥ 1.50.0 / ≥ 0.5.0 / ≥ 0.1.0 / ≥ 2.0.0 / ≥ 0.2.0 / ≥ 0.30.0 / ≥ 1.0.0 / ≥ 0.1.0)
  • Mistral: no pin needed — mistralai 1.x and 2.x both work. Version 2 moved the client import to from mistralai.client import Mistral (1.x keeps from mistralai import Mistral). On mistralai 2.0–2.9.1, pip may install an older OpenTelemetry train to satisfy that release's own cap; it still meters normally, and mistralai>=2.9.2 dropped the cap.
  • Never set OTEL_SDK_DISABLED=true — it turns OpenTelemetry off globally, TokenPolice's own capture included.

Node

Everything is in the one npm i token-police install. Install the provider package you already use (they're optional peer dependencies) and TokenPolice taps it.

Provider / frameworkMeteredStreamingTool spansNotes
OpenAI (openai)autovia frameworkOn openai 7.x, pass the module — see below
Anthropic (@anthropic-ai/sdk)autovia frameworkPrefer the namespace import in instrumentModules
Cohere (cohere-ai)v2 client
Amazon Bedrock (@aws-sdk/client-bedrock-runtime)Converse usage read directly
Google Gemini (@google/genai)1.x and 2.x
OpenRouter · Cerebras · Together · Groq · Mistraleach provider's own package
Hugging Face (@huggingface/inference)must be wired before you construct InferenceClient
Vercel AI SDK (ai + @ai-sdk/*)manual — alwayscommunity providers need instrumentModules.aiSdkProviders
LangChainautoadd the token-police-langchain companion
LlamaIndex (@llamaindex/*)autoESM: pass each provider namespace under instrumentModules.llamaIndex
OpenAI Agents JS (@openai/agents)autoruns on the Responses API

openai 7.x — pass the module. TokenPolice's built-in OpenAI capture auto-discovers openai 4–6. On 7.x, auto-discovery declines the package and prints a warning at startup: chat-completion calls still run and are still pre-flight checked, but they report 0 tokens, so budgets never accumulate. Passing the module fixes it completely:

import OpenAI from "openai";
tp.init({ /* … */ instrumentModules: { openAI: OpenAI } });

That patches your own copy directly, and chat completions meter normally on openai 7 with the right model, token counts, and composition. The Responses API, images, audio, and embeddings are metered on openai 7 either way. See Node & ESM.

Verified with

These come from the lockfiles of the apps we run the SDK against, so they're exact resolved versions.

LibraryVerified
openai7.9.0 (with instrumentModules), 4.104.0
@anthropic-ai/sdk0.123.0
@google/genai2.20.0
@aws-sdk/client-bedrock-runtime3.1124.0
ai (Vercel AI SDK)7.0.90
@ai-sdk/anthropic / -gateway / -xai / -openai-compatible3.0.6 / 4.0.72 / 2.0.92 / 1.0.53
@langchain/core / -openai / -anthropic / -google-genai / langgraph1.2.9 / 1.5.11 / 1.5.9 / 2.3.0 / 1.4.13
llamaindex / @llamaindex/openai / -anthropic / -google0.12.1 / 0.4.22 / 0.3.26 / 0.4.0
cohere-ai / @mistralai/mistralai / together-ai8.1.0 / 2.6.4 / 0.50.0
@openai/agents / @huggingface/inference0.17.0 / 4.13.28
@cerebras/cerebras_cloud_sdk / @openrouter/sdk1.91.0 / 1.2.93

groq-sdk is supported by the code but isn't covered by a running app in our fleet, so treat it as untested at that tier.

Beyond chat

Embeddings, image generation, text-to-speech, transcription, video, and OCR are metered too, each tagged with its own operation so a rule can target it separately from chat.

Known gaps — these are not metered today: rerank endpoints (Cohere, Voyage), moderation endpoints, and OpenAI's images.edit / images.createVariation. If you need them counted, wrap the call yourself with protect() and a provider hint. Never protect() something already in the tables above — you'll count it twice.

Next