LLM Cost Calculator — JavaScript source
Estimate LLM costs per request or per month at billion-token scale — with realistic prompt-cache hit rates, four-lane pricing, and side-by-side model comparison from a dated pricing snapshot.
This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
/**
* LLM Cost Calculator - per-million-token cost math for LLM workloads.
*
* Language: JavaScript (ES2020+, runs unmodified in Node 16+ and modern browsers)
* Source: CosmoDev polyglot showcase port of the LLM Cost Calculator tool,
* ported from src/lib/llmCost.ts (the canonical TypeScript
* implementation), with the tokensPerDollar helper inlined from
* src/lib/ai/models.ts so this file stays dependency-free.
* Tool page: https://dev.cosmolabs.org/tools/llm-cost-calculator
* License: display source - part of CosmoDev's polyglot tool pages.
*
* Design goals:
* - Pure + deterministic; never throws.
* - Functionally equivalent to the TS reference: same inputs -> same outputs
* (a null rate means "unpriced" and propagates to a null cost).
* - Self-contained: stdlib only (no npm dependencies, no model snapshot).
*
* Formula: ((inputTokens / 1e6) * inputPerM + (outputTokens / 1e6) * outputPerM)
* * requests * (batch ? 0.5 : 1). Model rates are NEVER hardcoded
* here - the caller supplies them (in the TS lib they flow from the
* model snapshot accessor; custom rates are the one exception).
*/
'use strict';
/** Multiplier applied to Batch API pricing (the standard 50% discount). */
export const BATCH_DISCOUNT = 0.5;
/**
* Price pair for a model or a custom rate card. `null` = unpriced.
*
* @typedef {Object} CostRates
* @property {number|null} inputPerM USD per 1M input tokens.
* @property {number|null} outputPerM USD per 1M output tokens.
*/
/**
* One workload to price.
*
* @typedef {Object} CostInput
* @property {number} inputTokens Input tokens per request.
* @property {number} outputTokens Output tokens per request.
* @property {number} [requests] Request count; defaults to 1.
* @property {boolean} [batch] Apply the BATCH_DISCOUNT multiplier.
*/
/**
* Pricing projection of a model. The full AiModel record (src/lib/ai/models.ts)
* carries a dozen non-pricing fields; only these three matter to cost math.
*
* @typedef {Object} Model
* @property {string} id
* @property {number|null} inputPerM
* @property {number|null} outputPerM
*/
/**
* Cost in USD for a workload, or null when either rate is unpriced:
* ((inputTokens/1e6)*inputPerM + (outputTokens/1e6)*outputPerM) * requests
* * BATCH_DISCOUNT when batch.
*
* @param {CostRates} rates
* @param {CostInput} input
* @returns {number|null}
*/
export function costFor(rates, input) {
if (rates.inputPerM === null || rates.outputPerM === null) return null;
const base =
(input.inputTokens / 1_000_000) * rates.inputPerM +
(input.outputTokens / 1_000_000) * rates.outputPerM;
return base * (input.requests ?? 1) * (input.batch ? BATCH_DISCOUNT : 1);
}
/**
* One row of a compareModels result.
*
* @typedef {Object} ModelCost
* @property {string} id
* @property {number|null} inputPerM
* @property {number|null} outputPerM
* @property {number|null} cost costFor with the model's rates.
* @property {number|null} tokensPerDollar 1e6 / outputPerM (null-safe).
*/
/** Project a model onto its CostRates pair. @param {Model} m @returns {CostRates} */
export function ratesFor(m) {
return { inputPerM: m.inputPerM, outputPerM: m.outputPerM };
}
/** Output tokens per USD: 1e6 / outputPerM. Null when unpriced. @param {Model} m @returns {number|null} */
export function tokensPerDollar(m) {
return m.outputPerM === null ? null : 1_000_000 / m.outputPerM;
}
/** String compare standing in for TS localeCompare (ids are ASCII slugs). @param {string} a @param {string} b @returns {number} */
const idAsc = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
/**
* Cost every requested model for one workload. Unknown ids are dropped.
* Sort: cost asc, nulls last, ties by id asc (byte-wise - ids are ASCII slugs).
*
* The TS original defaults `models` to the live snapshot (allModels()); this
* port has no snapshot dependency, so the model list is always explicit.
*
* @param {string[]} modelIds
* @param {CostInput} input
* @param {Model[]} models
* @returns {ModelCost[]}
*/
export function compareModels(modelIds, input, models) {
const rows = [];
for (const id of modelIds) {
const m = models.find((mo) => mo.id === id);
if (m === undefined) continue;
rows.push({
id,
inputPerM: m.inputPerM,
outputPerM: m.outputPerM,
cost: costFor(ratesFor(m), input),
tokensPerDollar: tokensPerDollar(m),
});
}
return rows.sort((a, b) => {
if (a.cost === null || b.cost === null) {
if (a.cost === null && b.cost === null) return idAsc(a.id, b.id);
return a.cost === null ? 1 : -1;
}
if (a.cost === b.cost) return idAsc(a.id, b.id);
return a.cost - b.cost;
});
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →