Skip to main content

Self-hosted cost-governance gateway for LLM APIs: per-model pricing, principal attribution, hard budget enforcement, cost/quality routing, semantic caching, and OTel GenAI observability.

Project description

costhelm

A self-hosted cost-governance gateway for LLM APIs. Your agents talk to one local HTTP endpoint; costhelm owns the provider keys and answers every call with the numbers that actually matter: what it cost, who spent it, and how much budget is left.

Most gateways treat cost as a report you read after the money is gone. costhelm treats it as a precondition: every call is projected at worst-case cost and admitted against a hard budget before any provider is contacted. A refusal is an HTTP 402 with the arithmetic in the body — limit, spend, projection, shortfall — and it costs $0, because nothing was sent.

call 4: ollama/phi4:latest — $0.017000 (total $0.047000) — 'Running budget checks before...'
call 5: REFUSED — session:budget-agent-demo would exceed its lifetime budget:
        spent $0.047000 of $0.050000, this call projects $0.016000

Features

Hard budgets Per-principal ceilings (tenant/project/user/agent/session, glob-able) with minute/hour/day/month/lifetime periods. Pre-call admission on a worst-case projection; spend is always re-derived from the ledger, never a parallel counter. Runtime overrides via POST /v1/budget — clamp a runaway session without a deploy.
Priced ledger One SQLite row per call, priced from a per-model pricing.yaml (glob patterns, cache-read/write and batch multipliers) and attributed to all five principal dimensions. CI fails if a configured default model would price at $0.
Tier routing + cascade A small router LLM classifies each prompt (TINY/LARGE/HUGE); the caller's declared role clamps the tier with floors and ceilings; candidates are ordered by cost, quality, or a tradeoff dial. Low-confidence answers escalate one tier — confidence is scored from structural signals, never a judge LLM.
Provider failover Eight providers behind one API (OpenAI, Gemini with a numbered key pool, OpenRouter, Ollama, Groq, Cerebras, NVIDIA, GitHub Models). RPM/RPD/TPM pacing, capability-aware picking (tools/vision/reasoning/structured), failure-class cooldowns — all configurable in routing.yaml.
Semantic cache Embed → cosine match → skip the provider entirely. A hit bills $0 and records the tokens as saved; truncated and empty completions are refused into the cache. Off by default, one line to enable.
Observability OTel spans with gen_ai.* attributes plus cost; two zero-build HTML dashboards; /v1/refusals captures the 402s that by design leave no span and no ledger row. Prompt/completion capture is off by default.
Optional auth One env var (COSTHELM_API_KEYS) guards /v1/* with bearer or X-API-Key. Off by default for localhost.

Quickstart

uvx costhelm serve

(or from a clone: uv sync && uv run costhelm serve)

Add a provider key to .env (see .env.example) — or none at all if Ollama is running locally:

curl -s localhost:8111/v1/chat -H 'Content-Type: application/json' \
  -d '{"prompt": "hello", "max_tokens": 50}'

Every response carries cost, budget, cache, and router_decision envelopes. Open http://localhost:8111/ for the dashboard.

To see budget enforcement end-to-end, run the example agent — it arms a $0.05 ceiling, spends it, and prints the 402:

uv run python examples/budget_agent.py

How a request flows

POST /v1/chat
  │
  1. build_context      normalise, estimate tokens, resolve principal, agent pin
  2. semantic cache     hit → return stored answer, bill $0, record tokens saved
  3. select_candidates  router-LLM tier classify → role clamp → cost/quality order
  4. dispatch           ┌ cascade loop ──────────────────────────────┐
                        │  for each candidate:                       │
                        │    budget admission (worst-case, pre-call) │──402
                        │    provider call (+1 retry, backoff)       │
                        │    structured-output validate/repair       │
                        │    confidence check → maybe escalate tier ─┘
                        │    meter → priced ledger row, OTel span
                        └ return text + cost/budget/cache envelopes

Each stage is a module in costhelm/pipeline/, and each is inert unless configured: with the shipped config files, costhelm behaves like a plain failover gateway.

Configuration

Four YAML files, three-layer resolution — an env-var path override wins, then ~/.costhelm/<name>.yaml, then the packaged default. costhelm paths prints what resolved where.

File Governs
pricing.yaml $/Mtok per model, cache/batch multipliers, quality weights
budgets.yaml Spend ceilings per principal (ships empty: nothing is refused)
routing.yaml Tiers, roles, ladders, escalation, provider limits, agent pins
cache.yaml Semantic cache (ships disabled)

Secrets and switches live in .env — see .env.example. A provider registers only if its key variable is set.

Client

from costhelm.client import CosthelmClient, BudgetExceeded

async with CosthelmClient() as gw:
    await gw.set_budget("session:run-42", 0.05, period="day")
    try:
        r = await gw.chat("hello", request={"session": "run-42", "auto_route": "worker"})
        print(r["text"], r["cost"]["total_usd"])
    except BudgetExceeded as e:
        print("refused:", e.envelope["shortfall_usd"])

The wire contract is plain HTTP JSON — any language works. The client holds no provider credential; that boundary is the point.

Deployment

deploy/ has systemd/launchd/Windows-service templates, a Modal wrapper, and a docker-compose file for a local Jaeger to receive the OTel spans. Docs: https://costhelm.com

Origins

costhelm grew out of an agentic-AI course project (a gateway serving a budget-aware agent runtime) and was extracted and restructured into a standalone framework.

License

MIT

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

costhelm-0.1.0.tar.gz (331.3 kB view details)

Uploaded Source

Built Distribution

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

costhelm-0.1.0-py3-none-any.whl (151.1 kB view details)

Uploaded Python 3

File details

Details for the file costhelm-0.1.0.tar.gz.

File metadata

  • Download URL: costhelm-0.1.0.tar.gz
  • Upload date:
  • Size: 331.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for costhelm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 968feb2008f04690ea2b827dc9273855c1118538b9a5a6238e75360033fe9f84
MD5 f13fb21034dd93139549829a0ef19c39
BLAKE2b-256 14fcc12d6cc05161b3acf1d540951320946caaaa108dd72899d326216ce26c6a

See more details on using hashes here.

File details

Details for the file costhelm-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: costhelm-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 151.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for costhelm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ae136d7051556cccd583063ab930e44de67751f9a31eaf0173e2bcb9c699660
MD5 b2d8f6accab266f46e02760bdb44e513
BLAKE2b-256 5de27fbde871af2b8faa5321eb38b8ecf8181fe0b26f50508d61e34c4ad0c9a7

See more details on using hashes here.

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