This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
annapurna-meter
The optional metering hook for Annapurna —
a thin, fail-safe wrapper that reports per-call LLM usage so spend can be
attributed per feature. Stdlib-only, no dependencies. Cost is computed
server-side from Annapurna's pricing tables — the SDK never sees prices, and it
never sends prompt or response content, only token counts and a feature_id.
It is fail-safe: recording appends to an in-memory queue and returns. A single background worker batches and posts; nothing on your call path blocks, raises, or touches the network. If Annapurna is down, misconfigured, or asleep, your application is unaffected. With no ingest URL/token configured, every call is a no-op.
It is also bounded: one worker thread per meter whatever your traffic, and a
capped queue (10,000 events). If the queue fills — a stalled endpoint, a burst —
the oldest events are dropped and counted on meter.dropped. Metering degrades;
your application does not.
Delivery and flush()
Events are sent when a batch fills (50) or after flush_interval seconds (5),
whichever comes first. An atexit hook flushes on normal shutdown with a short
deadline, so a script that exits immediately still delivers.
Call meter.flush() explicitly where the worker may not get scheduled — a
serverless handler that freezes between invocations, or before a hard exit:
meter.flush() # returns True if the queue drained, False on timeout
meter.flush(timeout=1) # never waits longer than you allow
Retries
A failed batch is retried (3 attempts, backing off ~1s / 4s / 15s with jitter) — enough to ride out a restart, a blip, or a sleeping instance waking up. A 4xx is not retried: a bad token or a malformed event fails the same way forever, so retrying only hammers the endpoint. 429 is retried, since it explicitly asks you to come back.
Retrying is safe because every attempt carries the same batch_id. The server
applies a batch once and recognises re-deliveries, so a retry after a timeout you
could not distinguish from a failure cannot double-charge a feature. Events only
count as lost after the final attempt, and then meter.dropped says so.
Tunable per meter: batch_size, flush_interval, queue_max, timeout,
max_attempts, retry_backoff.
Install
pip install annapurna-meter
Use
Recommended — wrap the client once (no per-call code):
from annapurna_meter import wrap
client = wrap(anthropic_client, feature_id="feature-threat-triage") # reads ENV
resp = client.messages.create(model="claude-sonnet-4-6", ...) # metered automatically
Provider is auto-detected; each call is recorded with its latency. Pass an
optional metadata={…} (e.g. environment, customer_id) for extra
attribution. Streaming/async calls use the explicit form below.
Explicit — one line per call:
from annapurna_meter import Meter
meter = Meter(feature_id="feature-threat-triage")
resp = anthropic_client.messages.create(model="claude-sonnet-4-6", ...)
meter.record_anthropic(resp) # <- the whole hook
Helpers: record_anthropic, record_openai, record_gemini,
record_openai_compatible, or the generic record(provider=…, model=…, tokens_in=…, tokens_out=…, feature_id=…).
Optimize mode (opt-in)
Meter(..., optimize=True) additionally emits privacy-safe signals — salted
hashes and counts, never prompt text — so Annapurna can surface measured
optimization opportunities (duplicate calls, uncached repeated prefixes). Off by
default; all work is off the call path, memory-bounded, and fail-safe. The SDK
fetches a per-tenant salt once (GET /api/hook/salt, same ingest token).
Config
| Env var | What it is |
|---|---|
ANNAPURNA_INGEST_URL |
e.g. https://app.example.com/api/hook/events |
ANNAPURNA_INGEST_TOKEN |
the per-workspace ingest token from the dashboard |
License
Apache-2.0. (The Annapurna server is AGPL-3.0; this client SDK is permissive so you can embed it in a proprietary app.)
Metadata
Release files for annapurna-meter 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| annapurna_meter-0.4.0.tar.gz | 23.5 kB | Without provenance | Details for annapurna_meter-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| annapurna_meter-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for annapurna_meter-0.4.0-py3-none-any.whl |
Total release size: 40.8 kB
Release files / annapurna_meter-0.4.0.tar.gz
| Download URL | annapurna_meter-0.4.0.tar.gz |
|---|---|
| Size | 23.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
620c36e9a8fe58233f509bf4942db2f29423aff4a1b94c59bde6b81b767ecc2d
|
|
BLAKE2b-256 checksum How to use checksums |
6c287a02aa29103b5626cab160c7d07046b4f2d2f62e6bc3e5d2b16820c86962
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / annapurna_meter-0.4.0-py3-none-any.whl
| Download URL | annapurna_meter-0.4.0-py3-none-any.whl |
|---|---|
| Size | 17.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06839f452eddc99d182638bf2635a958ea62cfa38e2de45d21815d688d76cb26
|
|
BLAKE2b-256 checksum How to use checksums |
bfc86d2071b2be366e1e7a7e7df6b3596ca4420e7daade822952225e62a54df3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Security for annapurna-meter 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.