compression with a quality contract

Adapters & Integration

Three paths to production: a one-line Python wrapper that compresses in-process, a standalone HTTP proxy that works with any SDK or framework, or distil wrap — a zero-config launcher that routes any existing command through the proxy automatically.


Path 1 — In-process: wrap(client)

Module: distil/adapters/anthropic.py

The fastest path for Python codebases already using the Anthropic SDK. Wrap your client once at construction time — all downstream messages.create calls are transparently compressed and cache-pinned with no call-site changes.

import anthropic
from distil.adapters.anthropic import wrap

# Before: plain Anthropic client
client = anthropic.Anthropic()

# After: one-line drop-in
client = wrap(anthropic.Anthropic())

# No other code changes — all calls compressed transparently
response = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    system="You are a helpful assistant.",
    messages=[{"role": "user", "content": "Analyse this log output…"}],
)

What the wrapper does

On every messages.create(**kwargs) call, the wrapper:

  1. Compresses the messages array via compress_messages():
    • User text blocks: Tier-0 lossless transforms (JSON minify + run collapse).
    • Tool result blocks with ≥ 6 lines: Tier-1 reversible digest, original stored in a local RestoreStore.
    • Assistant text, tool_use, and image blocks: passed through unchanged.
  2. Pins the cache prefix via place_cache_control(): marks the last stable system block with {"cache_control": {"type": "ephemeral"}}, so the first call pays the cache-write price and every subsequent call pays the ~0.1× cache-read price.
  3. Forwards the modified kwargs to the real client.messages.create.

The RestoreStore

Digested blocks embed an 8-hex SHA-256 handle in their compressed text. The RestoreStore maps handles to originals locally — it is never sent to the model and costs zero tokens. To recover an original:

from distil.adapters.anthropic import compress_messages

compressed, store = compress_messages(messages)
# store.handles → frozenset of all active handles
original = store.expand("a3f92b1c")  # retrieve original by handle

Design properties


Path 2 — Provider proxy: distil proxy

Module: distil/proxy.py

A lightweight HTTP proxy that sits between your client and the real LLM API. It intercepts POST /v1/messages, POST /v1/chat/completions, and POST /v1/responses requests, compresses the messages array, and forwards the modified request to the upstream. All other paths and methods pass through unchanged.

This approach works with any SDK, framework, or language — you do not need to touch your application code at all.

$ distil proxy --port 8788 --upstream https://api.anthropic.com
distil proxy listening on http://127.0.0.1:8788
  → upstream: https://api.anthropic.com

Point your client at the proxy

Anthropic SDK

Python

import anthropic
client = anthropic.Anthropic(
    base_url="http://localhost:8788"
)
OpenAI SDK

Python / Node

import openai
client = openai.OpenAI(
    base_url="http://localhost:8788/v1",
    api_key="…"
)
LiteLLM

Multi-provider

litellm.completion(
    api_base="http://localhost:8788",
    model="anthropic/claude-…",
    messages=[...]
)
LangChain

Python

from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(
    base_url="http://localhost:8788"
)

Proxy flags

FlagDefaultDescription
--port8788Port to listen on
--upstreamhttps://api.anthropic.comReal LLM API base URL (no trailing slash)
--lossless-onlyoffApply Tier-0 transforms only — safe for subscription / OAuth sessions

Response headers

The proxy adds two custom headers to compressed responses:

Threading model

The proxy uses Python's ThreadingHTTPServer — each incoming connection is handled in its own thread, so concurrent requests from multiple clients are supported. It is intentionally simple and easy to audit.


Path 3 — Transparent: distil wrap

Module: distil/proxy.py · wrap_run()

When you don't own the agent's code — it's a CLI, a third-party tool, or any process that reads ANTHROPIC_BASE_URLdistil wrap gives you Path 2's compression with none of the setup. It spawns the proxy on an ephemeral port, injects the env var into the child, runs your command, and tears everything down on exit (flushing genuine savings to your ledger).

$ distil wrap -- claude -p "summarize this repo"
distil wrap → proxy http://127.0.0.1:54xxx (upstream https://api.anthropic.com)
  → ANTHROPIC_BASE_URL=http://127.0.0.1:54xxx
  → recording genuine savings → distil leaderboard

Everything after -- runs verbatim and its exit code is propagated. Use --env-var to point a different variable (e.g. an OpenAI-compatible client) at the proxy. See the CLI reference for all flags.


Choosing your path

wrap(client)distil proxy
LanguagePython onlyAny (HTTP)
SDK requiredAnthropic SDK (duck-typed)Any base_url-honoring client
SetupOne import + one callStart proxy process, update base_url
RestoreStore accessDirect Python objectNot exposed (stateless proxy)
Cache-control pinningAutomatic via place_cache_control()Not currently applied
lossless-only modePass lossless_only=True to compress_messages--lossless-only flag
Multi-language teamsNoYes

Honest note: live provider path

The proxy forwards to the real upstream. Any request that goes through distil proxy will hit the live provider API and consume your quota / billing. Ensure you have a valid API key set in the client — the proxy does not add or modify authorization headers.

The --runner anthropic flag on distil certify also routes to the live Anthropic API. It is implemented and wired up, but marked UNVERIFIED in the README until you run it with a real key. The offline deterministic runner (the default) is what powers all corpus measurements.