Skip to content

CostCalculator

CostCalculator computes LLM call costs from token counts and model pricing. It ships with built-in pricing defaults for Gemini models and supports custom pricing via explicit configuration or JSON files.

Import

import {
  CostCalculator,
  ModelPricing,
  PricingConfig,
  CostCalculatorOpts,
  CostResult,
} from "@modernpath/agent-framework";

Constructor

new CostCalculator(opts?: CostCalculatorOpts)

CostCalculatorOpts

interface CostCalculatorOpts {
  pricing?: PricingConfig;
  pricingConfigPath?: string;
  onMissingModel?: "warn" | "skip" | "error";
}
Property Type Default Description
pricing PricingConfig -- Explicit pricing config. Takes priority over file and defaults.
pricingConfigPath string -- Path to a JSON pricing config file. Overrides LLM_PRICING_CONFIG_PATH env var.
onMissingModel string "warn" Behavior when a model is not found: "warn" logs once and returns null, "skip" returns null silently, "error" throws.

Pricing Resolution Order

  1. Explicit pricing object passed to constructor
  2. JSON file at pricingConfigPath or LLM_PRICING_CONFIG_PATH environment variable
  3. Built-in Gemini defaults

Methods

calculate

calculate(params: {
  model: string;
  inputTokens: number;
  outputTokens: number;
  thinkingTokens?: number;
}): CostResult | null

Calculates the cost for a single LLM call. Returns null if the model is unknown and onMissingModel is "skip" or "warn".

Parameter Type Description
model string Model identifier (e.g. "gemini-2.5-flash"). Supports prefix matching.
inputTokens number Number of input tokens.
outputTokens number Number of output tokens.
thinkingTokens number Number of thinking tokens (optional). Falls back to output pricing if thinkingPer1M is not configured.

CostResult

interface CostResult {
  cost: number;
  model: string;
}

currency (getter)

get currency(): string

Returns the currency string from the pricing config (default: "USD").

Pricing Types

PricingConfig

interface PricingConfig {
  models: Record<string, ModelPricing>;
  currency?: string;
}

ModelPricing

interface ModelPricing {
  inputPer1M: number;
  outputPer1M: number;
  thinkingPer1M?: number;
}

All rates are per 1 million tokens in USD (or the configured currency).

Built-in Gemini Pricing

The following models have built-in pricing defaults:

Model Input / 1M Output / 1M Thinking / 1M
gemini-2.0-flash $0.10 $0.40 --
gemini-2.5-flash $0.15 $0.60 $0.60
gemini-2.5-pro $1.25 $10.00 $10.00
gemini-3-flash $0.15 $0.60 $0.60
gemini-3-pro $1.25 $5.00 $5.00

Model names support prefix matching: "gemini-2.5-flash-preview-2026-01" matches the "gemini-2.5-flash" pricing entry.

Custom Pricing File

Create a JSON file with the PricingConfig structure:

pricing.json
{
  "currency": "USD",
  "models": {
    "gemini-2.5-flash": {
      "inputPer1M": 0.15,
      "outputPer1M": 0.60,
      "thinkingPer1M": 0.60
    },
    "my-custom-model": {
      "inputPer1M": 2.50,
      "outputPer1M": 10.00
    }
  }
}

Load it via environment variable or constructor option:

export LLM_PRICING_CONFIG_PATH=./config/pricing.json

Code Example

import { CostCalculator } from "@modernpath/agent-framework";

// Use built-in defaults
const calc = new CostCalculator();

// Calculate cost for a single call
const result = calc.calculate({
  model: "gemini-2.5-flash",
  inputTokens: 5000,
  outputTokens: 1500,
  thinkingTokens: 2000,
});

if (result) {
  console.log(`Cost: $${result.cost.toFixed(6)}`);
  // Cost: $0.002475
  // = (5000/1M * $0.15) + (1500/1M * $0.60) + (2000/1M * $0.60)
}

console.log(`Currency: ${calc.currency}`); // "USD"

// Aggregate costs across a trace
const spans = traceStore.getAllSpans().filter((s) => s.kind === "llm");
let totalCost = 0;
const byModel: Record<string, number> = {};

for (const span of spans) {
  const model = span.genAiAttributes?.["gen_ai.request.model"] ?? "unknown";
  const input = span.genAiAttributes?.["gen_ai.usage.input_tokens"] ?? 0;
  const output = span.genAiAttributes?.["gen_ai.usage.output_tokens"] ?? 0;

  const cost = calc.calculate({ model, inputTokens: input, outputTokens: output });
  if (cost) {
    totalCost += cost.cost;
    byModel[model] = (byModel[model] ?? 0) + cost.cost;
  }
}

const traceCost: TraceCost = {
  total: totalCost,
  byModel,
  currency: calc.currency,
};