Skip to main content

agent_metering

CI License: MIT Python 3.10+

Language-agnostic LLM cost metering for B2B SaaS — point any OpenAI / Anthropic client at the HTTP proxy (Node, Go, Java, PHP, Python, curl, …).

MIT open sourceCONTRIBUTING · SECURITY · Code of Conduct

Install

pip install llm-agent-metering
# optional extras:
# pip install "llm-agent-metering[dashboard]"
# pip install "llm-agent-metering[example]"

From GitHub (latest main):

pip install "git+https://github.com/prantakhandaker/agent_metering.git"

Any language (recommended)

Run the proxy once, then set your SDK base URL to it. No SDK install in the app language required.

pip install llm-agent-metering
python -m uvicorn agent_metering.proxy:app --host 0.0.0.0 --port 8787
Provider Base URL / env
OpenAI http://127.0.0.1:8787/proxy/openai/v1OPENAI_BASE_URL
Anthropic http://127.0.0.1:8787/proxy/anthropicANTHROPIC_BASE_URL
Azure .../proxy/azure/v1AZURE_OPENAI_BASE_URL

Optional per-user / feature headers (stripped before upstream):

  • X-User-Id (preferred) or X-Customer-Id
  • X-Feature
  • Or OpenAI body field user / Anthropic metadata.user_id

Defaults: env AGENT_METERING_CUSTOMER_ID / AGENT_METERING_FEATURE, else default.

For OpenAI-compatible streaming (stream: true), the proxy automatically adds stream_options: {"include_usage": true} when the client omitted it, so the final SSE chunk includes a real usage block. Anthropic streams already emit usage without this option. Exact token counts from the usage block are logged (not content estimates).

Optional granularity headers (also stripped before upstream):

  • X-Call-Id or X-Step — tag a single step inside an agent loop (rolls up under X-Feature)
  • X-Unit-Id — business unit / artifact id for cost-per-unit reporting
  • X-Correlation-Id + optional X-Attempt — link retries; prior attempts become retry_attempt

Spend is written to local SQLite (agent_metering.db) in WAL mode with batched flushes (every ~200ms or 50 records). A crash loses at most the current in-memory batch; committed data survives.

Per-customer allowances

Hard stop when a customer exceeds a monthly spend cap (off by default). In agent_metering.config.json:

"enforcement": {
  "enabled": true,
  "status_code": 429,
  "allowances": {
    "acme_corp": { "max_spend_usd": 50.0, "period": "calendar_month" }
  }
}

status_code may be 429 (default) or 402. When exceeded, the proxy returns JSON {"error":"allowance_exceeded", ...} and does not call the upstream provider. Checks use an in-memory spend cache refreshed when usage is flushed to SQLite.

Dashboard:

python -m streamlit run examples/dashboard.py   # pip install "llm-agent-metering[dashboard]"

Node

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: "http://127.0.0.1:8787/proxy/openai/v1",
  defaultHeaders: { "X-User-Id": "user_42" },
});

await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "Hi" }],
});

Full script: examples/proxy_node_example.mjs.

curl

curl http://127.0.0.1:8787/proxy/openai/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-User-Id: user_42" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hi"}]}'

Go

client := openai.NewClient(
  option.WithAPIKey(os.Getenv("OPENAI_API_KEY")),
  option.WithBaseURL("http://127.0.0.1:8787/proxy/openai/v1"),
  option.WithHeader("X-User-Id", "user_42"),
)

Docker sidecar

docker compose -f examples/docker-compose.sidecar.yml up --build

App containers only need OPENAI_BASE_URL / ANTHROPIC_BASE_URL pointing at http://metering-proxy:8787/proxy/....

Or wrap a local process:

python -m agent_metering run --start-proxy -- python your_app.py

Python-only shortcut (optional)

Same venv install auto-patches OpenAI / Anthropic SDKs (no base URL change):

pip install llm-agent-metering
# run your Python app — no import required

Opt out: AGENT_METERING_AUTO=0. Demo: python examples/auto_instrument_example.py.

Also detects FastAPI/Flask/Django request users and OpenAI user= when present.

Who this is for / not for

For: Any stack that can set an LLM HTTP base URL (or env) and needs per-customer / per-user / per-feature spend.

Not for: Full tracing/evals (Langfuse), or replacing multi-provider gateways you already run (LiteLLM / Portkey) unless you put this proxy in front.

Why

Flat API rate limits do not protect margin. Agent workloads are open-ended: tool loops and long contexts can burn tokens quietly. Metering per customer/feature surfaces that before margin disappears.

Project layout

Primary (any language): proxy.py, providers/, cli.py
Python convenience: autoload.py (.pth), instrument.py, user_detect.py, frameworks.py
Shared: config.py, core.py, storage.py, context.py

Tests

pytest

Releasing

Maintainers publish to PyPI via GitHub Actions Trusted Publishing (no API token in secrets).

  1. One-time on pypi.org: Publishing → Pending publisher
    • Project: llm-agent-metering
    • Owner: prantakhandaker
    • Repository: agent_metering
    • Workflow: publish.yml
    • Environment: leave empty
  2. Bump version in pyproject.toml to match the release tag.
  3. Tag and release:
# version in pyproject.toml must match the tag
git tag v0.4.0
git push origin v0.4.0
# then GitHub → Releases → Draft release from that tag → Publish

Publishing workflow: .github/workflows/publish.yml.

License

MIT

Download files

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

Source Distribution

llm_agent_metering-0.4.0.tar.gz (44.4 kB view details)

Uploaded Source

Built Distribution

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

llm_agent_metering-0.4.0-py3-none-any.whl (36.8 kB view details)

Uploaded Python 3

File details

Details for the file llm_agent_metering-0.4.0.tar.gz.

File metadata

  • Download URL: llm_agent_metering-0.4.0.tar.gz
  • Upload date:
  • Size: 44.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for llm_agent_metering-0.4.0.tar.gz
Algorithm Hash digest
SHA256 eb6c598155bbca492b6fe2c690f2015c546cb7237144ae2cecbbb28569ea376d
MD5 f4eb79822fa1fa09d21569cad233ec23
BLAKE2b-256 da15c0809e61a5640c4615ffe62793a066256b66cc540ec892119b836c969c23

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_agent_metering-0.4.0.tar.gz:

Publisher: publish.yml on prantakhandaker/agent_metering

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

File details

Details for the file llm_agent_metering-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for llm_agent_metering-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 afd58c68a98f09b89fda1ba32c18797901f8967aff4dd213326a90262dafcd60
MD5 4523f5129856fcad3990eb8408432108
BLAKE2b-256 503d828bed42f7c2530a7b20fd48a3712bbffaa54c3b5d7696fa5a6e75615910

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_agent_metering-0.4.0-py3-none-any.whl:

Publisher: publish.yml on prantakhandaker/agent_metering

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

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 files

0.3.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page