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 tokenMETERGRAPH_INGEST_URL— optional override; defaults to the hosted HTTPS endpointMETERGRAPH_CAPTURE_TEXT=1— opt in to content capture globally; default is metadata-onlyMETERGRAPH_DISABLED=1— process kill switchMETERGRAPH_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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00c5988def9588630f5b8c657df1933d637b53755bd7bfde3539388ab1cfe380
|
|
| MD5 |
8f598878217b6d9c77888d8458c4f068
|
|
| BLAKE2b-256 |
20fd3f0455f133d6775f597d40d5b1823855626afd934238e0f0dd93706d4f69
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a529765fd2dd092515aac298f48ceb293621c468612914157668856534e18541
|
|
| MD5 |
7804a0039dd3d638240d3a0af0df5010
|
|
| BLAKE2b-256 |
87c42368ab3335962a4829614c518b07575335ed91476c68666768cb8df29ca5
|