Skip to main content

Fire-and-forget LLM spend capture for Metergraph

Project description

metergraph (Python)

Zero-runtime-dependency capture for OpenAI, Anthropic, and Gemini clients. wrap() initializes capture from the environment, so setup is one line per client; call metergraph.init(...) before the first wrap() only to pass options in code.

import metergraph
from openai import OpenAI

# Anthropic() and google-genai's genai.Client() wrap the same way.
client = metergraph.wrap(OpenAI())
metergraph.set_session("ticket-123")

with metergraph.route("ticket-classifier", unit="answer", capture_text=True):
    model = metergraph.model_for("ticket-classifier", default="gpt-4.1-mini")
    client.chat.completions.create(model=model, messages=[...])

# Emit this after the user-visible task resolves. It shares the bounded async
# transport and contains no prompt or output content.
metergraph.record_outcome(
    "ticket-classifier",
    model=model,
    task_completed=True,
    feedback_score=1,
    turns_to_resolution=2,
    escalated=False,
)

Configuration:

  • METERGRAPH_APP_TOKEN — required bearer token
  • METERGRAPH_INGEST_URL — optional override; defaults to the hosted HTTPS endpoint
  • METERGRAPH_CAPTURE_TEXT=1 — opt in to content capture globally; default is metadata-only
  • METERGRAPH_DISABLED=1 — process kill switch
  • METERGRAPH_QUEUE_SIZE, METERGRAPH_BATCH_SIZE, METERGRAPH_FLUSH_SECONDS

Delivery is bounded and off the request path. Queue overflow or a collector outage drops capture and increments internal counters; it never changes the provider call. Each wire batch is bounded to 512 KiB after optional gzip. capture_text=True or False on route() overrides the global content policy for that route. Config reads are ETag-aware and fail open to the default model. record_outcome requires a stable session ID and the model actually used so a session-sticky canary can compare task completion and optional feedback, turn-count, escalation, abandonment, edit-distance, and regeneration signals.

OpenAI Batch API output JSONL is captured per inference when a wrapped client.files.content() / retrieve_content() result is read. Anthropic message batches are captured per inference while iterating a wrapped client.messages.batches.results() result. Run result consumption inside a route() context so the asynchronous batch retains its product route. Batch rows carry real per-result usage and the batch pricing flag; job-management polls themselves are not miscounted as model calls.

Set up with an AI coding agent

Paste this into Claude Code, Codex, Cursor, or any coding agent inside the codebase you want instrumented:

Instrument this codebase's LLM API costs with the `metergraph` PyPI package
(https://github.com/PioneerSquareLabs/metergraphsdk): pip install metergraph,
then wrap every OpenAI()/AsyncOpenAI(), Anthropic()/AsyncAnthropic(), and
genai.Client() construction in place, e.g. client = metergraph.wrap(OpenAI()).
wrap() returns the same client and initializes itself from the environment:
METERGRAPH_APP_TOKEN is required (capture is silently off without it) and
METERGRAPH_INGEST_URL is only for self-hosted servers. Add both to
.env.example, and never commit a real token. Capture is metadata-only (tokens,
latency, model, no prompt/completion content) and fail-open, so do not change
call sites, arguments, or error handling; sync, async, and streaming work
unchanged. Attribution to the calling function is automatic; optionally pin
stable names on key LLM-calling functions with @metergraph.track. On
serverless, call metergraph.flush() before the handler returns. When done,
list every client you wrapped and flag LLM calls made outside the official
openai / anthropic / google-genai SDKs, since those are not captured.

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

metergraph-0.1.0.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

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

metergraph-0.1.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: metergraph-0.1.0.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for metergraph-0.1.0.tar.gz
Algorithm Hash digest
SHA256 00c5988def9588630f5b8c657df1933d637b53755bd7bfde3539388ab1cfe380
MD5 8f598878217b6d9c77888d8458c4f068
BLAKE2b-256 20fd3f0455f133d6775f597d40d5b1823855626afd934238e0f0dd93706d4f69

See more details on using hashes here.

File details

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

File metadata

  • Download URL: metergraph-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for metergraph-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a529765fd2dd092515aac298f48ceb293621c468612914157668856534e18541
MD5 7804a0039dd3d638240d3a0af0df5010
BLAKE2b-256 87c42368ab3335962a4829614c518b07575335ed91476c68666768cb8df29ca5

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