Skip to main content

CacheLens

Non-invasive prompt cache instrumentation for LLM API apps. Wrap your client in one line. Get terminal reports, JSON exports, and OTEL metrics.

Prompt caching gives steep discounts on cached tokens — but nothing tells you whether your app is actually getting cache hits, or why not. CacheLens wraps your Anthropic, Gemini, or OpenAI client and reports cache hit rate, cost, savings, and the money you're leaving on the table, broken down by prompt layer.

See docs/architecture.md for the full design.

Install

pip install cachelens                # core + rich
pip install cachelens[anthropic]     # + Anthropic SDK
pip install cachelens[gemini]        # + Gemini SDK
pip install cachelens[openai]        # + OpenAI SDK
pip install cachelens[otel]          # + OpenTelemetry
pip install cachelens[all]           # everything

Quickstart

import anthropic
from cache_lens import wrap

client = wrap(anthropic.Anthropic())
# ... use client exactly as before; report prints on exit

Explicit session boundary with exports:

from cache_lens import CacheLens

with CacheLens(client, json_export="report.json", otel=True) as session:
    agent.run(...)        # your code, unchanged
report = session.report

Suppress the terminal report in CI with CACHE_LENS_TERMINAL=0.

Custom pricing

CacheLens ships a default price table, but you can override or extend it without forking — handy when a new model lands. User entries merge over the defaults:

# in-memory dict (native format, USD per 1M tokens)
wrap(client, pricing={"openai": {"gpt-5": {"input": 1.25, "output": 10.0, "cache_read": 0.125}}})

# or a JSON file (native or LiteLLM model_prices_and_context_window.json format)
wrap(client, pricing="pricing.json")

Or point at a file process-wide with CACHE_LENS_PRICING=/path/to/pricing.json. A bad pricing file falls back to defaults rather than breaking the run. See docs/architecture.md for the full design.

A pricing= argument applies to that wrapped client's session only — two clients with different overrides don't leak into each other. For a process-wide override use the env var or cache_lens.pricing.load(...).

Privacy & what gets captured

CacheLens never sends your prompts anywhere. By default it doesn't even keep them: each request segment is reduced to (role, SHA-256 hash, length) at capture time — enough for prefix diffing and layer attribution — so memory stays bounded and no prompt content lingers in the process heap. Reports (terminal, JSON, OTEL) contain only aggregates: token counts, costs, hit rates, and tips. Pass capture_content=True to wrap() / CacheLens to retain full text for your own inspection.

Async clients (AsyncAnthropic, AsyncOpenAI, generate_content_async) are instrumented like sync ones. Streaming calls (stream=True, messages.stream) are not instrumented yet — they are counted and shown as "skipped" in the report, so missing tokens are visible rather than silently under-counted.

The wrapper is a proxy: isinstance(wrapped, anthropic.Anthropic) is False. Call wrapped.unwrap() to reach the original client where identity matters.

How this helps you develop LLM applications

Prompt caching only pays off if your prompt's prefix is stable and byte-identical across calls — but most agent loops accumulate per-turn state (timestamps, counters, mutating progress trackers) that silently breaks the prefix without anyone noticing. The API still works fine, the bill just stays high. CacheLens turns that invisible problem into a concrete, iterable workflow during development:

  1. Wrap your client once and run your normal dev/test loop — no changes to your app logic required.
  2. Read the layer table to see whether your prompt is actually splitting into stable layers (system prompt, schema/context, conversation) or collapsing into one big conversation blob — the latter is a strong signal that something near the top of your prompt changes every turn.
  3. Use the tips as a diagnosis, not just a metric. "No stable prompt prefix detected" tells you why your hit rate is 0% and what to fix (move static content first, make it byte-identical); "X% of input tokens are uncached" tells you how much headroom restructuring is worth before you spend time on it.
  4. Re-run after each change and compare Savings, Cached/Hit Rate, and whether the tips changed — this is the feedback loop that tells you whether a refactor (e.g. splitting prompt-building into a stable prefix and a volatile trailer) actually moved the needle, before you ever look at a billing dashboard.

See examples/queryargus.md for a real before/after walkthrough of this loop on a 30-turn Gemini agent.

Status

v1.1. Implemented: wrapper interception (sync and async) with request capture (content-free by default — hash + length only), provider extraction

  • capture (Anthropic + Gemini + OpenAI), content-based layer classification (longest-common-prefix → named system_prompt / context / conversation layers, cross-referenced against actual cache reads), terminal/JSON/OTEL outputs, per-session overridable pricing, latency percentiles, skipped-call accounting, tests. Pending: streaming usage extraction (currently counted as skipped), cache-lens run CLI injection, and cross-run static/semi-static separation (see docs/architecture.md and docs/improvement-plan.md).

Develop

pip install -e .[dev]
pytest

Metadata

Release files for cachelens 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cachelens 1.1.0
File Size Uploaded Provenance Actions
cachelens-1.1.0.tar.gz 42.7 kB With provenance Details for cachelens-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cachelens 1.1.0
File Interpreter ABI Platform Actions
cachelens-1.1.0-py3-none-any.whl Python 3 none any Details for cachelens-1.1.0-py3-none-any.whl

Total release size: 67.5 kB

Release files / cachelens-1.1.0.tar.gz

Download URL cachelens-1.1.0.tar.gz
Size 42.7 kB
Tags Source
SHA-256 checksum
How to use checksums
c9a72aeabdd390fa70e94c7cac0ace0b906ea5b13e15e2ec8714f3c10830d857
BLAKE2b-256 checksum
How to use checksums
4588efd4b3ec577dfd087d5cd62ef86c821a3686efaa17dc7c6c644125cc7907
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 12, 2026.

Transparency log

Release files / cachelens-1.1.0-py3-none-any.whl

Download URL cachelens-1.1.0-py3-none-any.whl
Size 24.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a2bd7ab0e7b99c6edfd380b49930cf50dba36141330e9939752b5a7e6fab776b
BLAKE2b-256 checksum
How to use checksums
2003d00c3ba840417bc7376063af520a1e13b0a06a4f1cb5adae7fa6c1a31ed5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 12, 2026.

Transparency log

Security for cachelens 1.1.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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cachelens-1.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 12, 2026.

Transparency log

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.

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