TokenPolice
Docs
Integrations

Supported providers & frameworks

The canonical list: every provider and framework TokenPolice meters, what it costs to install, and the caveats worth knowing.

This is the single support surface. If your provider is in the first table you are done after Get started — install the SDK, call tp.init(), and your calls are metered. Frameworks sometimes need one extra step, listed in the second table.

For which library versions are supported, see Supported versions. This page is about what is covered, not which release of it.

Providers

Every provider below is metered on the base installpip install token-police / npm i token-police — with the two exceptions marked in the table. In Node, install the provider package you already use (they are optional peer dependencies) and TokenPolice taps it.

Streaming is metered everywhere in this table. Usage is recorded when the stream finishes, so a streamed call shows up with the same token counts and cost as a non-streamed one.

ProviderPythonNodeNotes
OpenAIbasebaseChat, Responses, images, audio and embeddings. On Node with openai 7 or newer, pass the module — see the caveat below
AnthropicbasebaseOn Node ESM, prefer the namespace import — see Node & ESM
Amazon BedrockbasebaseConverse usage is read from the response
Google Geminibasebase
CoherebasebaseChat and embeddings
MistralbasebaseChat, embeddings, OCR, transcription, FIM, speech (2.x); mistralai 1.x and 2.x — see the import note below
GroqbasebaseGroq's own client. Groq's OpenAI-compatible endpoint is metered too — see the note below
OpenRouterbasebase
Cerebrasbasebase
TogetherbasebaseChat and images
Hugging FacebasebaseNode: instrument before your app constructs its inference client
xAI (Grok)token-police[xai]baseThe Python extra installs xAI's own client; nothing extra is needed to meter it
Voyagetoken-police[voyageai]Embeddings only. Python only — there is no Node path today

Node + openai 7: pass the module

On Node, chat completions made with openai 7 or newer are only metered when you hand the module to init():

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

Without it the calls still run and are still checked against your rules, but they are recorded with zero tokens, so budgets never accumulate. The SDK prints a warning at startup when it spots this. Responses-API, image, audio and embedding calls are unaffected. Full detail: Node & ESM.

OpenAI-compatible base URLs are usually already metered. If you reach a provider by pointing the openai client at its OpenAI-compatible endpoint, the OpenAI instrumentation meters that call like any other, and the SDK reads the base URL to attribute it to the right provider. It recognises around two dozen hosts — api.groq.com, openrouter.ai, api.together.xyz, api.fireworks.ai, api.deepinfra.com, api.deepseek.com, api.x.ai, api.mistral.ai, api.perplexity.ai, api.cerebras.ai, api.cohere.com, api.moonshot.ai, api.minimax.io, api.novita.ai, api.z.ai, open.bigmodel.cn, api.studio.nebius.com, ai-gateway.vercel.sh, plus the Azure OpenAI, Bedrock and Vertex URL patterns. A host it doesn't know is still metered; it is just recorded under openai, with the sanitized base URL attached so you can tell it apart.

So reach for protect() only for something we do not instrument at all: an in-house client, a raw fetch against a provider's REST API, or a provider SDK that isn't in this table. Never protect() a call that already runs through an instrumented client — including an OpenAI-compatible one — or it is counted twice.

Beyond chat

Non-chat calls are metered too and land in the dashboard tagged with their own operation, so a rule can target them separately from chat:

operationCovered
embeddingBroad coverage in both SDKs
image_genOpenAI Images, Google Imagen, Together, Hugging Face; Vercel AI SDK image models (Node)
audio_ttsOpenAI, Hugging Face, Gemini audio output, Mistral speech (mistralai 2.x, Python); Vercel AI SDK speech models (Node)
audio_sttOpenAI transcription and translation, Mistral Voxtral, Hugging Face; Vercel AI SDK transcription models (Node)
video_genGoogle Veo; Vercel AI SDK video models (Node)
ocrMistral

A rule on operation is embedding is handy for RAG: it stops a runaway re-embed loop without touching your chat traffic.

Known gaps. Rerank endpoints (Cohere, Voyage), moderation endpoints, and OpenAI images.edit / images.createVariation are not metered. Cover them with protect() and a provider= hint if you need them counted.

Frameworks

FrameworkPythonNodeTool spansWiring
LangChain / LangGraphtoken-police[langchain]token-police-langchain companion (@langchain/core 0.3.x and 1.x)automaticLangChain
Vercel AI SDKbase (ai + @ai-sdk/*)manual, alwaysVercel AI SDK
LlamaIndextoken-police[llamaindex]base; instrumentModules.llamaIndex on ESMautomatic (Node)LlamaIndex
CrewAItoken-police[crewai]manualCrewAI
Pydantic AItoken-police[pydantic-ai]automaticPydantic AI
OpenAI Agents SDKtoken-police[openai-agents]base (@openai/agents)automaticOpenAI Agents SDK
Agnotoken-police[agno]manualinstall the extra, then tp.init() as usual

Tool spans say whether the tool calls inside an agent run appear as their own steps in the dashboard. Where the column says manual — as it does for hand-rolled tool loops and MCP tools in any framework — the model calls are still metered and still enforced; the tool steps simply don't get their own entry in the trace.

Reroute does not switch the model on every framework

A Reroute rule does not switch the model on some frameworks — including LangChain, LangGraph, LlamaIndex, Pydantic AI, and the Vercel AI SDK. Those calls still run on the original model. Confirm a swap actually happens in your app before you enforce this in production. Blocking and metering are unaffected. See Actions.

Python extras

pip install "token-police[langchain]"    # or llamaindex, pydantic-ai, openai-agents, agno, xai, voyageai
pip install "token-police[crewai]"       # CrewAI has its own extra and is not part of [all]
pip install "token-police[all]"          # every framework extra except crewai

[all] deliberately leaves CrewAI out: CrewAI supports Python 3.10–3.13 but not 3.14 yet, so keeping it separate is what lets [all] install everywhere. If you use CrewAI, install token-police[crewai] (on its own, or alongside [all]).

Pins & conflicts to know about

These are environment caveats, not things TokenPolice enforces — but they trip people up at install time:

  • Mistral (Python): mistralai 1.x and 2.x are both supported — no pin needed. On 2.x the client import moved: from mistralai.client import Mistral (on 1.x it stays 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 works, and mistralai>=2.9.2 drops the cap.
  • CrewAI (Python): installs may print a benign resolver warning — safe to ignore. Strict resolvers (uv, Poetry, pip-tools) sometimes need a two-step install: CrewAI first, then token-police[crewai]. Set CREWAI_DISABLE_TELEMETRY=true to quiet CrewAI's own tracing noise.
  • Don't downgrade TokenPolice's own dependencies. Older versions of them undercount Bedrock Converse usage; the pins that ship with the SDK are the tested ones.
  • Never set OTEL_SDK_DISABLED=true. It turns off tracing globally — including TokenPolice's own instrumentation, so nothing gets metered.

Next