tokenworth
v0.2.0
Published
LLM cost calculator powered by LiteLLM pricing — 2400+ models, auto-cost on API calls
Readme
tokenworth
One function to estimate LLM cost. Pass a model name + your input and output (raw text or exact token counts). Get back the token usage and estimated USD cost.
Pricing data sourced from LiteLLM — automatically covers 2400+ models across OpenAI, Anthropic, Google, Mistral, Cohere, and more.
No external API calls. No sign-up. All pricing is built into the package — works fully offline.
Install
npm install tokenworthQuick start
import cost from "tokenworth";
// With exact token counts (pass numbers)
cost("gpt-4o", 1000, 500);
// → { model: "gpt-4o", inputTokens: 1000, outputTokens: 500, totalTokens: 1500, estimatedCost: 0.0075 }
// With raw text (auto-counts tokens)
cost("gpt-4o", "Write a greeting email.", "Hello! Great to hear from you.");
// → { model: "gpt-4o", inputTokens: 6, outputTokens: 8, totalTokens: 14, estimatedCost: 0.000095 }
// Unknown model → null
cost("unknown/fake-model", 100, 50);
// → nullThat's it. One import, one call.
Usage examples
1. Pass token counts (numbers)
import cost from "tokenworth";
const result = cost("gpt-4o-mini", 2000, 1000);
// ↑ ↑
// input tokens output tokens
console.log(result.estimatedCost); // 0.00092. Pass raw text (auto-counts tokens)
import cost from "tokenworth";
const result = cost(
"gpt-4o",
"Explain quantum computing in simple terms.", // input text
"Quantum computing uses qubits...", // output / response text
);
console.log(result);
// {
// model: "gpt-4o",
// inputTokens: 8,
// outputTokens: 5,
// totalTokens: 13,
// estimatedCost: 0.00007
// }3. Call an AI model and get the cost automatically
The callModel function makes the actual API call and returns the response + cost. Uses the OpenAI-compatible endpoint.
import { callModel } from "tokenworth";
const { data, cost } = await callModel({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello world" }],
apiKey: process.env.OPENAI_API_KEY,
});
console.log(data.choices[0].message.content); // ← normal AI response
console.log(cost.estimatedCost); // ← auto-calculated costWorks with any OpenAI-compatible provider — just set baseUrl:
// Azure OpenAI
callModel({ model: "gpt-4o", messages, apiKey, baseUrl: "https://my-resource.openai.azure.com" });
// LiteLLM proxy
callModel({ model: "gpt-4o", messages, apiKey, baseUrl: "http://localhost:4000" });
// Ollama (no API key needed)
callModel({ model: "llama3", messages, baseUrl: "http://localhost:11434" });4. Wrap your existing AI SDK call
Auto-extracts the output text and counts tokens from the real API response.
import { trackCost } from "tokenworth";
import OpenAI from "openai";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const { data, cost } = await trackCost({
model: "gpt-4o",
input: "Hello world",
fn: () => openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello world" }],
}),
});
console.log(data.choices[0].message.content); // ← normal response, unchanged
console.log(cost.estimatedCost); // ← auto-calculatedAlso works with Anthropic SDK, raw fetch, or any async function.
5. Custom pricing for models not in the catalog
import cost from "tokenworth";
cost("my-private-model", 1000, 500, {
pricing: {
"my-private-model": { input: 0.005 / 1000, output: 0.02 / 1000 },
},
});
// → { model: "my-private-model", inputTokens: 1000, outputTokens: 500, ... }6. Use the lower-level functions directly
import { calculateCost, countTokens, getPricing, isLocalModel } from "tokenworth";
countTokens("Hello world"); // 2
calculateCost("gpt-4o", 1000, 500); // 0.0075
getPricing("claude-3-sonnet"); // { input: 0.000003, output: 0.000015 }
isLocalModel("ollama"); // true
// Models only in LiteLLM (not in manual list) work too:
getPricing("gemini-2.0-flash-001"); // { input: 0.00000015, output: 0.0000006 }
getPricing("mistral-large-latest"); // { input: 0.000008, output: 0.000024 }What you get back
cost() returns CostResult | null:
type CostResult = {
model: string; // the model name you passed in
inputTokens: number; // token count for input
outputTokens: number; // token count for output
totalTokens: number; // inputTokens + outputTokens
estimatedCost: number; // USD cost
};Returns null when the model is not found in the pricing catalog and no custom pricing is provided.
callModel() returns CallModelResult:
type CallModelResult = {
data: Record<string, unknown>; // raw API response (OpenAI ChatCompletion format)
cost: CostInfo; // cost breakdown
};trackCost() returns TrackCostResult<T>:
type TrackCostResult<T> = {
data: T; // your original SDK response, unchanged
cost: CostInfo;
};CostInfo:
type CostInfo = {
model: string;
inputTokens: number;
outputTokens: number;
totalTokens: number;
estimatedCost: number;
inputChars: number;
outputChars: number;
durationMs: number;
};Pricing data
This package embeds LiteLLM's comprehensive pricing database, covering 2400+ models:
- OpenAI: GPT-4o, GPT-4o-mini, GPT-4-turbo, GPT-4, GPT-3.5-turbo, o1, o3, etc.
- Anthropic: Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku, Claude 4, etc.
- Google: Gemini 1.5/2.0 Flash/Pro, etc.
- Mistral: Mistral Large, Small, Nemo, etc.
- Cohere: Command R, Command R+, etc.
- Meta: Llama 3.x (through providers)
- Amazon Bedrock, Azure, GCP Vertex AI hosted models
- Local models (Ollama, etc.) are detected automatically and priced at $0
Refresh the pricing data at any time:
npm run refresh-pricingFull API reference
cost(model, input, output, options?)
| Param | Type | Description |
|-----------|-----------------------------|--------------------------------------------------|
| model | string | Model name. Vendor prefixes auto-resolved. |
| input | string \| number | Raw text (auto-tokenized) or exact token count. |
| output | string \| number | Raw text (auto-tokenized) or exact token count. |
| options | { pricing?: Record<string, { input: number, output: number }> } | Custom pricing overrides (optional). |
Returns CostResult \| null.
callModel(options)
| Option | Type | Description |
|-----------------|-----------------------------------|-----------------------------------------------|
| model | string | Model name. |
| messages | { role: string; content: string }[] | Chat messages. |
| apiKey? | string | API key (default: ""). |
| baseUrl? | string | API base URL (default: https://api.openai.com). |
| temperature? | number | Sampling temperature. |
| maxTokens? | number | Max output tokens. |
| topP? | number | Nucleus sampling. |
| onCost? | (info: CostInfo) => void | Callback when cost is calculated. |
Returns Promise<CallModelResult>.
trackCost(options)
| Option | Type | Description |
|-----------|-----------------------------------|---------------------------------------------|
| model | string | Model name. |
| input | string | Input text sent to the AI. |
| fn | () => Promise<T> | Your AI SDK call. |
| onCost? | (info: CostInfo) => void | Callback when cost is calculated. |
| pricing?| Record<string, ModelPricing> | Custom pricing overrides. |
Returns { data: T, cost: CostInfo }.
Other named exports
| Function | Description |
|-----------------------|----------------------------------------------|
| calculateCost(model, inTokens, outTokens, pricing?) | Cost from token counts. |
| countTokens(text, model?) | Count tokens in text. |
| getPricing(model, custom?) | Look up model pricing. |
| isLocalModel(model) | Check if model is free/local. |
| extractResponseText(response) | Extract text from AI SDK response. |
| estimateCost({ model, inputTokens, outputTokens, pricing? }) | Build full CostInfo. |
| resolveModel(name) | Resolve alias/vendor-prefixed name. |
How it works
- Pricing catalog is compiled from LiteLLM's open-source pricing database at build time — 2400+ models, no network requests at runtime
- Token counting uses
@dqbd/tiktoken(OpenAI's open-source encoding, runs locally) - Vendor prefixes (
openai/,anthropic/) are auto-stripped before lookup - Dated model names (e.g.
claude-sonnet-4-20250514) are aliased to base models callModelmakes the actual API call and returns both response and cost- The original SDK response passes through unmodified —
trackCostjust reads it
Requirements
- Node.js 18+ (ESM)
License
MIT
