← All posts
Provider notes5 min read

Inject, steer, observe — what a proxy can actually do about caching, per provider

Three verdicts cover every provider we route. On some a proxy can create cache hits; on some it can only raise their probability; on most it can only watch. Badging those the same would be a lie.

If a proxy sits between your app and seventeen AI providers, what can it actually do about prompt caching on each one? We had to answer that question honestly per provider, because the answer decides which badge an agent gets on the dashboard — and a badge that says "optimised" over a mechanism that cannot optimise is a lie with a UI. The answers collapse into three verdicts, and the boundaries between them are worth knowing even if you never use a proxy, because they are really facts about the providers' own caching APIs.

Inject: the proxy can create hits that would not otherwise occur

Injection means mutating the request body — placing a cache_control breakpoint, splitting a system prompt around a timestamp — so a call that would have missed, reads. It requires two things at once: an API with explicit cache markers, and an auth scheme that does not sign the body.

Three routes qualify: Anthropic direct, Claude on Vertex (OAuth bearer, no body hash, and the rawPredict body is the Anthropic format with the model moved into the URL), and Bedrock — but only for requests that arrive with a Bedrock API key. The same Bedrock model under SigV4 is unreachable, because SigV4 signs the body's SHA-256 and a mutated request fails outright. The verdict attaches to the request's credential, not to the provider — one agent can be injectable on Monday's traffic and not on Tuesday's, if its auth changes.

Mistral is the interesting fourth: its API accepts an explicit cache key, so a proxy can supply one deterministically — a different lever than Anthropic's breakpoints, but a real one: the proxy's action changes what the cache does.

Steer: the proxy can raise the odds, but cannot place a marker

A middle class of providers cache automatically but accept hints that affect placement — routing-affinity fields that make it likelier two related requests land on infrastructure sharing a warm cache. xAI, Fireworks, Baseten and Cloudflare take this shape.

Steering is real: a well-chosen affinity key measurably raises hit probability. But it is a different kind of claim than injection, and the difference is the whole point of this post. An injected breakpoint either produced a read or it did not — attributable per call from the usage object. A steering hint raises a probability; no individual hit can be attributed to it, because that hit might have happened anyway. Badging a steered agent "optimised" in the same green as an injected one would let the strong claim launder the weak one. The dashboard distinction is mechanism-accurate on purpose: we did X and here is the read it caused versus we did Y, which correlates with more reads.

Observe: the proxy can only tell you the truth

Everyone else — OpenAI and the bulk of the OpenAI-compatible cluster — caches automatically, above their own thresholds, with no control surface at all: no breakpoint, no key, no hint. A proxy's honest verdict there is observe: measure reads and writes, price them at each model's real multipliers, and diagnose why hits are not happening.

Observation is worth more than the verdict makes it sound, because automatic caching still fails for exactly the reasons explicit caching does — a timestamp in the prefix, an unstable tool order, a prefix under the threshold — and the provider will not tell you which. Per-call prefix fingerprints answer that even where nothing can be injected. But observation must never wear optimisation's badge: "we found why your cache misses" is diagnosis, and the customer fixes their prompt; "we made it hit" is treatment. A product that bills for treatment must not bill for diagnosis dressed as treatment.

Two sub-cases make observe-status sharper. Passthrough (OpenRouter): cache_control markers pass through to whichever upstream it fronts, so the caller can inject through it, but the proxy attributing results would be claiming credit for behaviour two hops away. And the zero-discount cache: one fast-inference host caches aggressively and charges cached tokens at the standard input rate — a cache that saves latency and not one cent. A "savings" figure rendered there would be a claim about a discount that does not exist, which is why the rendering rule is null, not $0.00 — the dash argument again.

Why the taxonomy is the product decision

Vigil charges for optimisation and monitors for free, which makes the verdict boundary a billing boundary: an agent can only ever be charged optimisation share on traffic where injection actually ran and its reads are attributable. Steered and observed traffic is monitored, diagnosed, and never billed as optimised — not because the engineering is humble but because the attribution is not there, and a figure without attribution is a figure we do not show. If you evaluate any caching-optimisation product, this is the question to ask it: on my provider, which verb do you actually have? The provider list and each one's verdict is on the FAQ.

What to do

Classify your own providers into the three verbs — check whether the API documents explicit cache markers or keys (inject), affinity or routing hints (steer), or automatic-only caching (observe) — and check what your auth scheme forbids: body-signing auth removes inject regardless of what the API supports. Then match your effort to the verb: on inject providers, invest in breakpoint placement and prefix stability; on steer providers, set the affinity hints and measure hit rate before and after; on observe providers, spend the same effort on prefix hygiene instead, because there the only optimiser with write access to your prompts is you.