Skip to main content

Alpha cost ledger utility for LLM and agent API responses.

Project description

RunCost

CI GitHub release npm PyPI Go Reference License: MIT Python 3.9+ TypeScript types

RunCost is a small alpha utility for answering one question:

What did this LLM or agent API call cost, and why?

It turns provider responses, framework usage objects, or normalized usage into a componentized cost ledger with input, cached input, output, reasoning, tool units, discounts, price sources, and warnings.

Install

Install from package registries:

pip install runcost-ai
npm install runcost
go get github.com/adamallcock/runcost/packages/go/ledger

Source checkout development paths:

python3 -m pip install git+https://github.com/adamallcock/runcost.git
PKG_TGZ=$(npm pack ./packages/javascript/core --silent)
npm install "./$PKG_TGZ"

The Python distribution name is runcost-ai; the import package and CLI are runcost. The npm package is runcost. The Go package is github.com/adamallcock/runcost/packages/go/ledger.

Default Price Catalog

RunCost includes an optional bundled source-cache catalog generated from llm-prices, LiteLLM, OpenRouter, models.dev, and reviewed official snapshots for targeted provider pricing gaps and redirects. It is package data, not fixture data.

Python: default_price_cards() / default_source_cache()

JavaScript/TypeScript: defaultPriceCards() / defaultSourceCache()

Go: DefaultPriceCards() / DefaultSourceCache()

One-Minute Examples

Python:

from runcost import from_response

response = {
    "model": "gpt-4.1-mini-2025-04-14",
    "usage": {
        "input_tokens": 36,
        "input_tokens_details": {"cached_tokens": 6},
        "output_tokens": 87,
        "output_tokens_details": {"reasoning_tokens": 12},
    },
}

price_cards = [{
    "schema_version": "0.1",
    "id": "openai:gpt-4.1-mini:example",
    "provider": "openai",
    "surface": "openai.responses",
    "model": "gpt-4.1-mini",
    "aliases": ["gpt-4.1-mini-2025-04-14"],
    "components": [
        {"usage_component": "input_uncached_tokens", "unit": "token", "price": {"amount": "0.40", "currency": "USD", "per": "1000000"}},
        {"usage_component": "input_cache_read_tokens", "unit": "token", "price": {"amount": "0.10", "currency": "USD", "per": "1000000"}},
        {"usage_component": "output_text_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
        {"usage_component": "output_reasoning_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
    ],
    "source": {"name": "example"},
}]

ledger = from_response(
    response,
    provider="openai",
    surface="openai.responses",
    model="gpt-4.1-mini",
    price_cards=price_cards,
)

print(ledger["total"])
print(ledger["components"])
print(ledger["warnings"])

TypeScript:

import { fromResponse } from "runcost";

// Using the same response and priceCards shape as the Python example above.
const ledger = fromResponse(response, {
  provider: "openai",
  surface: "openai.responses",
  model: "gpt-4.1-mini",
  priceCards
});

console.log(ledger.total);
console.log(ledger.components);
console.log(ledger.warnings);

Go:

package main

import (
    "fmt"

    ledger "github.com/adamallcock/runcost/packages/go/ledger"
)

func main() {
    priceCards := []any{
        ledger.Object{
            "schema_version": "0.1",
            "id":             "openai:gpt-4.1-mini:example",
            "provider":       "openai",
            "surface":        "openai.responses",
            "model":          "gpt-4.1-mini",
            "aliases":        []any{"gpt-4.1-mini-2025-04-14"},
            "components": []any{
                ledger.Object{
                    "usage_component": "input_uncached_tokens",
                    "unit":            "token",
                    "price": ledger.Object{"amount": "0.40", "currency": "USD", "per": "1000000"},
                },
                ledger.Object{
                    "usage_component": "output_text_tokens",
                    "unit":            "token",
                    "price": ledger.Object{"amount": "1.60", "currency": "USD", "per": "1000000"},
                },
            },
            "source": ledger.Object{"name": "example"},
        },
    }

    cost := ledger.FromResponse(
        ledger.Object{
            "model": "gpt-4.1-mini-2025-04-14",
            "usage": ledger.Object{
                "input_tokens":  36,
                "output_tokens": 87,
            },
        },
        ledger.Object{
            "provider": "openai",
            "surface":  "openai.responses",
            "model":    "gpt-4.1-mini",
        },
        priceCards,
        nil,
    )

    fmt.Println(cost["total"])
}

Already have normalized usage? Use the deterministic calculator directly:

from runcost import calculate_cost

ledger = calculate_cost(
    usage_ledger={
        "schema_version": "0.1",
        "provider": "openai",
        "surface": "openai.responses",
        "model": {"requested": "gpt-4.1-mini"},
        "components": [
            {"name": "input_uncached_tokens", "quantity": "30", "unit": "token"},
            {"name": "output_text_tokens", "quantity": "75", "unit": "token"},
        ],
    },
    price_cards=price_cards,
)

Main APIs

Job Python JavaScript/TypeScript Go
Price normalized usage calculate_cost(...) calculateCost(options) CalculateCost(options)
Price a provider response from_response(...) fromResponse(response, options) FromResponse(response, options, priceCards, discountPolicies)
Aggregate call ledgers aggregate_cost_ledgers(...) aggregateCostLedgers(options) AggregateCostLedgers(...)
Use framework outputs from_langsmith_run(...), track_langchain_costs(...), and more fromVercelAISDKStreamFinish(...), createRunCostVercelOnFinish(...), and more FromLangSmithRun(...), FromSemanticKernelTelemetry(...), and more
Load price sources price_cards_from_json_file(...), price_cards_from_openrouter_models(...) priceCardsFromJSONFile(...), priceCardsFromOpenRouterModels(...) PriceCardsFromJSONFile(...), PriceCardsFromOpenRouterModels(...)
Use bundled default catalog default_price_cards() defaultPriceCards() DefaultPriceCards()
Add custom prices Pass price_cards Pass priceCards Pass price_cards in options
Apply discounts Pass discount_policies Pass discountPolicies Pass discount_policies in options
Audit decisions debug_trace=True debugTrace: true "debug_trace": true
Fail on ambiguity mode="strict" mode: "strict" mode: "strict"
CLI checks runcost price-cards, runcost fixture-check N/A N/A

Supported Inputs

Fixture-backed surfaces include OpenAI Responses and Chat Completions, Anthropic Messages, OpenRouter, Gemini and Vertex generateContent, AWS Bedrock Converse, Cohere Chat and Rerank, OpenAI-compatible providers such as Meta, Groq, xAI, Mistral, DeepSeek, Azure OpenAI, and Hugging Face Inference Providers, plus selected framework objects from LangChain, Vercel AI SDK, OpenAI Agents SDK, LlamaIndex, Haystack, LiteLLM, AutoGen/AG2, LangSmith, Semantic Kernel, and OpenRouter SDK paths.

See supported surfaces for the current matrix.

Custom Prices And Discounts

RunCost treats provider pricing as data. You can pass user price cards for private rates, exact aliases, service tiers, long-context prices, historical effective dates, tool units, or internal billing units.

discounts = [{
    "schema_version": "0.1",
    "id": "openai-contract-4pct",
    "match": {"provider": "openai"},
    "adjustment": {"type": "percentage_discount", "value": "4"},
}]

The returned ledger records selected price sources, applied discounts, and any warning that prevents the total from being fully explained.

Fixtures are behavioral conformance tests, not a complete model-price database. Use source adapters, reviewed source-cache snapshots, or the optional bundled default catalog for upstream catalog data; see price data strategy.

Python:

from runcost import DEFAULT_PRICE_SOURCE_PRIORITY, default_price_cards, from_response

ledger = from_response(
    response,
    provider="openai",
    surface="openai.responses",
    model="gpt-4.1-mini",
    price_cards=default_price_cards(),
    price_source_priority=DEFAULT_PRICE_SOURCE_PRIORITY,
)

TypeScript:

import { DEFAULT_PRICE_SOURCE_PRIORITY, defaultPriceCards, fromResponse } from "runcost";

const ledger = fromResponse(response, {
  provider: "openai",
  surface: "openai.responses",
  model: "gpt-4.1-mini",
  priceCards: defaultPriceCards(),
  priceSourcePriority: DEFAULT_PRICE_SOURCE_PRIORITY
});

Warnings

RunCost is designed to be boring. When it cannot confidently price something, it returns a structured warning such as unknown_model, component_unpriced, price_stale, stream_usage_missing, or provider_reported_cost_mismatch. Use strict mode in tests or reconciliation flows when warnings should fail.

CLI

The Python package installs a lightweight CLI:

runcost price-cards --source-type user-pricing --input prices.json
runcost fixture-check fixtures/my-case.json

Read Next

Status

RunCost is alpha software. The core behavior is fixture-backed across Python, JavaScript/TypeScript, and Go, and alpha packages are published to PyPI, npm, and Go module tags. Smoke costs may use sample price cards; use provider exports or dashboard reconciliation before treating a total as invoice-exact.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

runcost_ai-0.1.13.tar.gz (340.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

runcost_ai-0.1.13-py3-none-any.whl (356.8 kB view details)

Uploaded Python 3

File details

Details for the file runcost_ai-0.1.13.tar.gz.

File metadata

  • Download URL: runcost_ai-0.1.13.tar.gz
  • Upload date:
  • Size: 340.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for runcost_ai-0.1.13.tar.gz
Algorithm Hash digest
SHA256 a4b8a9c1601b41af0ede52259918634dc2dc8c5cc5c4ec19a2d4dcb1885e3427
MD5 ec649612df911ee4f8cc97904b4db24c
BLAKE2b-256 1567a5251ef38f42769aa66a973f39197c6837e3e3193361edbeae10795d2076

See more details on using hashes here.

Provenance

The following attestation bundles were made for runcost_ai-0.1.13.tar.gz:

Publisher: release.yml on adamallcock/runcost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file runcost_ai-0.1.13-py3-none-any.whl.

File metadata

  • Download URL: runcost_ai-0.1.13-py3-none-any.whl
  • Upload date:
  • Size: 356.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for runcost_ai-0.1.13-py3-none-any.whl
Algorithm Hash digest
SHA256 88efaa46274c88cc6b891b1c5fa7e8485eaed1e59fb6ba01b07b0aa8dc2deac9
MD5 4ec4f86d03236e5e785b8755964fe546
BLAKE2b-256 c8c0d80ecf7ca4ea5ddc18d754539b9d03cc3d956e22c79561178de95d652ca5

See more details on using hashes here.

Provenance

The following attestation bundles were made for runcost_ai-0.1.13-py3-none-any.whl:

Publisher: release.yml on adamallcock/runcost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page