Skip to main content

Client-side rate limiting for the Claude API. Never sees your API key.

Project description

llm-governor

Client-side rate limiting for the Claude API. Stop before the server has to say no.

This library never sees your API key. It wraps calls you make with your own client, and reads only anthropic-ratelimit-* response headers. No credentials are required, requested, logged, or stored.

pip install llm-governor

Why

Claude's Messages API enforces three independent limits per model: requests per minute (RPM), input tokens per minute (ITPM), and output tokens per minute (OTPM). Blow any one of them and you get a 429.

Most retry-on-429 code reacts after the failure. llm-governor mirrors the server's own token bucket locally, corrects itself from the rate-limit headers on every response, and paces your requests so the 429 never happens.

It also understands cached input. On most Claude models, cache_read_input_tokens do not count toward ITPM. A naive limiter that counts every input token will throttle you to a fraction of your real throughput; this one tracks your rolling cache-hit rate and reserves only what actually counts.

Quick start

import anthropic
from llm_governor import Governor

client = anthropic.Anthropic()          # your key, your client
gov = Governor(model="claude-sonnet-5") # knows nothing about keys

with gov.slot(messages=messages, max_tokens=1024) as slot:
    resp = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        messages=messages,
    )
    slot.observe(resp)   # feeds headers + usage back in

The first call runs against conservative defaults. From the second call onward, the governor knows your real limits because the API told it.

Async

gov = Governor(model="claude-sonnet-5", max_concurrency=8)

async def worker(messages):
    async with gov.aslot(messages=messages, max_tokens=1024) as slot:
        resp = await client.messages.create(...)
        slot.observe(resp)
        return resp

await asyncio.gather(*(worker(m) for m in batch))

Live dashboard

pip install "llm-governor[dashboard]"
llm-governor demo          # simulated workload, no API key needed
from llm_governor.dashboard import Dashboard

with Dashboard(gov):
    run_my_batch()
╭─ llm-governor · claude-sonnet-5 ─────────────────────╮
│  RPM   ████████████████░░░░   812 / 1000             │
│  ITPM  ███████░░░░░░░░░░░░░   1.4M / 2.0M            │
│  OTPM  ██████████████████░░   361K / 400K            │
│                                                      │
│  cache  78.0%                        94 req/min      │
│  flight     7                        231 done        │
│  429s       0                        3.2s waited     │
╰────────────────────────────── live ──────────────────╯

Bars turn amber below 25% headroom and red below 10%.

Dry run

See whether a workload would throttle, without waiting for it:

gov = Governor(model="claude-sonnet-5", dry_run=True)
# ... replay your workload ...
print(gov.snapshot()["throttled_seconds"])

Options

Option Default Meaning
model "claude-sonnet-5" Limits are per-model; use one governor per model
rpm / itpm / otpm conservative Starting guesses, overridden by headers
headroom 0.90 Fraction of the real limit to use; leaves margin for bursts
max_concurrency None Cap simultaneous in-flight requests
dry_run False Compute waits but never sleep

On credentials

The header allowlist in llm_governor.headers.ALLOWED_HEADERS is explicit and tested. scrub() is the only path by which headers enter this library, and a test asserts that x-api-key and authorization never survive it. If you extend this library, do not replace that with dict(response.headers).

Notes and limits

  • State is per-process. For multiple workers sharing one org limit, divide headroom by your worker count, or wait for the planned Redis backend.
  • Input estimation is character-based and approximate. Pass estimated_input explicitly if you have a real count from the token-counting endpoint.
  • Batch API requests have separate limits and are not covered.
  • max_tokens is reserved pessimistically and refunded once the real output size is known.

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

llm_rate_governor-0.1.0.tar.gz (14.5 kB view details)

Uploaded Source

Built Distribution

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

llm_rate_governor-0.1.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for llm_rate_governor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b937583b51b0a78b01278f939ccb2b09a8f3620a4889bc2fa6e4189b93238574
MD5 77d8878d194dd40447dcab4481ac3674
BLAKE2b-256 bf3b56d06d24b6e5f3948c7922c83f9fced4066891bb648824f75e695186030a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for llm_rate_governor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c5749bca8216fb09b78accdcb13a9ff85ef3f3c7fd5e03fa142c6e9fdac0a4b5
MD5 aceb3a777cda700cefff237482f6cc9b
BLAKE2b-256 30d6c6942a67995438d5e48418b27cd39e5ab18f43fc95f554baf432b3c5ddec

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