Description
Summary
The same logical request, sent through AI Gateway with two different AI SDK majors, is
charged differently: the cache-creation ("cache write") term is missing entirely from
the gateway's returned cost when the request goes through the ai@7 /
@ai-sdk/gateway@4 path (specificationVersion: 'v4'). On ai@6 /
@ai-sdk/gateway@3 ('v3') the same term is charged correctly.
input, cache_read and output are all priced correctly on both paths. Exactly one
term — cache creation — is dropped on v4.
This is under-billing (Vercel charges less than the provider list price the docs
promise), so it is presumably not intentional.
Environment
|
arm A |
arm B |
ai |
6.0.159 |
7.0.52 |
@ai-sdk/gateway |
3.0.96 |
4.0.41 |
GatewayLanguageModel.specificationVersion |
v3 |
v4 |
ai-gateway-protocol-version header |
0.0.1 |
0.0.1 (unchanged) |
Model: anthropic/claude-haiku-4.5 · finalProvider: anthropic · ZDR +
disallowPromptTraining enabled · cache_control: { type: "ephemeral", ttl: "1h" } on the
system prompt · Node 24 · same gateway API key / team for both arms.
Published Anthropic rates for Haiku 4.5: input $1/MTok, 5m write $1.25/MTok,
1h write $2/MTok, cache hit $0.10/MTok, output $5/MTok.
Observed
arm A — ai@6.0.159 + @ai-sdk/gateway@3.0.96 (spec v3) — CORRECT
Anthropic usage (providerMetadata.anthropic.usage):
input_tokens 13
cache_creation_input_tokens 19,818
cache_creation.ephemeral_1h_input_tokens 19,818
cache_read_input_tokens 0
output_tokens 4
gateway.inputInferenceCost = 0.039649
13 x $1/M + 19,818 x $2/M = 0.000013 + 0.039636 = 0.039649 <-- exact match
gateway.outputInferenceCost = 0.00002 ( = 4 x $5/M ) <-- exact match
gateway.cost = 0.039669
arm B — ai@7.0.52 + @ai-sdk/gateway@4.0.41 (spec v4) — cache write billed $0
Anthropic usage (providerMetadata.anthropic.usage):
input_tokens 13
cache_creation_input_tokens 19,819
cache_creation.ephemeral_1h_input_tokens 19,819
cache_read_input_tokens 0
output_tokens 4
gateway.inputInferenceCost = 0.000013
13 x $1/M = 0.000013 <-- exact match
expected with cache write:
13 x $1/M + 19,819 x $2/M = 0.039651 <-- NOT charged
gateway.outputInferenceCost = 0.00002
gateway.cost = 0.000033 (vs 0.039669 on v3, ~1,200x less)
Anthropic reports the cache-creation tokens in both arms, so the write really happens;
only the gateway's pricing of it differs.
Isolation: on v4, cache read is still priced correctly
Second call on the same cache key (v4 path), so it is a read instead of a write:
input_tokens 13 · cache_read_input_tokens 19,819 · cache_creation 0
gateway.inputInferenceCost = 0.0019949
13 x $1/M + 19,819 x $0.10/M = 0.000013 + 0.0019819 = 0.0019949 <-- exact match
So on the v4 path: input OK, cache-read OK, output OK, cache-creation dropped.
Why we suspect the v4 request path specifically
GatewayLanguageModel forwards the call options to the gateway verbatim — getArgs() is
just { ...optionsWithoutSignal } posted as the JSON body. So the only thing that changes
between the two arms on the wire is the call-options schema (LanguageModelV3CallOptions
vs LanguageModelV4CallOptions). The ai-gateway-protocol-version header is 0.0.1 in
both majors, and the client-side files that touch cost
(gateway-generation-info.ts, gateway-spend-report.ts) are unchanged between 3.0.96 and
4.0.41 apart from optional-headers handling — i.e. the cost is computed server-side.
That points at the server-side cost computation for the v4 payload shape having lost the
cache-creation term. Possibly related: AI SDK v7 split token usage into
inputTokenDetails.{noCacheTokens,cacheReadTokens,cacheWriteTokens} where v6 exposed
cachedInputTokens; a consumer-side instance of the same class of bug is
PostHog/posthog#63136 ("AI OTel mapping drops AI SDK v7 cache and reasoning usage,
producing incorrect costs").
Impact
Any team on ai@7 + Anthropic + prompt caching is under-charged by the full
cache-creation component of every request. For agent workloads (large cached system
prompts, many turns) cache creation is a large fraction of the true cost, so the
gateway-reported cost can be a small fraction of the provider list price.
Because it under-bills, it is also invisible to the usual "my bill is too high" reports,
and it silently corrupts anything downstream that trusts providerMetadata.gateway.cost
(cost dashboards, per-request budget caps, usage-based billing built on top of the gateway).
Also observed (separate, minor)
ai@6.0.159 accepts an instructions option but silently ignores it — in the reproduction below
the 19.8k-token system prompt was never sent (total input_tokens was 14) and no warning
was emitted. Flagging in case it is unintended in that major.
Question
Is this a bug, or an intentional discount / promotion on the v4 path?
If it is intentional, it would help to have it documented — the pricing docs currently
say AI Gateway charges the provider's list price with no markup, and the Automatic
Caching docs describe Anthropic cache writes as 1.25x the base input rate — and to know
whether the v3 path will be brought in line. If it is a bug, please say whether earlier
usage will be trued up, so downstream cost tracking can be adjusted accordingly.
Reproduction
Two directories, one dependency set each, identical probe:
import { generateText } from "ai";
import { createGateway } from "@ai-sdk/gateway";
// Unique prefix so the call is guaranteed to be a cache WRITE, and long enough to be cacheable.
const filler = Array.from({ length: 900 }, (_, i) =>
`Rule ${i}: when handling record ${i}, verify the checksum and log the outcome deterministically.`
).join("\n");
const system = `CACHE-KEY-NONCE ${Date.now()}\n${filler}`;
const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY });
const res = await generateText({
model: gateway("anthropic/claude-haiku-4.5"),
// NOTE: ai@7 rejects system messages inside `messages` ("Use the instructions option
// instead"), while ai@6 silently ignores `instructions`. So each arm uses the form its
// own major supports; the resulting upstream request is equivalent, as confirmed by
// Anthropic reporting ~19.8k cache_creation tokens in both arms.
// ai@6: messages: [{ role: "system", content: system, providerOptions: {...} }, user]
// ai@7: instructions: { role: "system", content: system, providerOptions: {...} }
instructions: {
role: "system",
content: system,
providerOptions: { anthropic: { cacheControl: { type: "ephemeral", ttl: "1h" } } },
},
messages: [{ role: "user", content: "Reply with the single word: ok" }],
maxOutputTokens: 16,
temperature: 0,
providerOptions: { gateway: { zeroDataRetention: true, disallowPromptTraining: true } },
});
console.log(JSON.stringify({
usage: res.usage,
gateway: res.providerMetadata?.gateway,
anthropic: res.providerMetadata?.anthropic,
}, null, 2));
Run each directory once and compare gateway.inputInferenceCost against
input x base + cacheWrite x (1.25x or 2x base) + cacheRead x 0.1x base.
AI SDK Version
- arm A (correct):
ai 6.0.159, @ai-sdk/gateway 3.0.96, @ai-sdk/provider 3.0.8
- arm B (cache write billed $0):
ai 7.0.52, @ai-sdk/gateway 4.0.41, @ai-sdk/provider 4.0.5
- Node 24
Code of Conduct
Description
Summary
The same logical request, sent through AI Gateway with two different AI SDK majors, is
charged differently: the cache-creation ("cache write") term is missing entirely from
the gateway's returned cost when the request goes through the
ai@7/@ai-sdk/gateway@4path (specificationVersion: 'v4'). Onai@6/@ai-sdk/gateway@3('v3') the same term is charged correctly.input,cache_readandoutputare all priced correctly on both paths. Exactly oneterm — cache creation — is dropped on v4.
This is under-billing (Vercel charges less than the provider list price the docs
promise), so it is presumably not intentional.
Environment
ai@ai-sdk/gatewayGatewayLanguageModel.specificationVersionv3v4ai-gateway-protocol-versionheader0.0.10.0.1(unchanged)Model:
anthropic/claude-haiku-4.5·finalProvider: anthropic· ZDR +disallowPromptTraining enabled ·
cache_control: { type: "ephemeral", ttl: "1h" }on thesystem prompt · Node 24 · same gateway API key / team for both arms.
Published Anthropic rates for Haiku 4.5: input
$1/MTok, 5m write$1.25/MTok,1h write
$2/MTok, cache hit$0.10/MTok, output$5/MTok.Observed
arm A —
ai@6.0.159+@ai-sdk/gateway@3.0.96(specv3) — CORRECTarm B —
ai@7.0.52+@ai-sdk/gateway@4.0.41(specv4) — cache write billed $0Anthropic reports the cache-creation tokens in both arms, so the write really happens;
only the gateway's pricing of it differs.
Isolation: on v4, cache read is still priced correctly
Second call on the same cache key (v4 path), so it is a read instead of a write:
So on the v4 path: input OK, cache-read OK, output OK, cache-creation dropped.
Why we suspect the v4 request path specifically
GatewayLanguageModelforwards the call options to the gateway verbatim —getArgs()isjust
{ ...optionsWithoutSignal }posted as the JSON body. So the only thing that changesbetween the two arms on the wire is the call-options schema (
LanguageModelV3CallOptionsvs
LanguageModelV4CallOptions). Theai-gateway-protocol-versionheader is0.0.1inboth majors, and the client-side files that touch cost
(
gateway-generation-info.ts,gateway-spend-report.ts) are unchanged between 3.0.96 and4.0.41 apart from optional-headers handling — i.e. the cost is computed server-side.
That points at the server-side cost computation for the v4 payload shape having lost the
cache-creation term. Possibly related: AI SDK v7 split token usage into
inputTokenDetails.{noCacheTokens,cacheReadTokens,cacheWriteTokens}where v6 exposedcachedInputTokens; a consumer-side instance of the same class of bug isPostHog/posthog#63136 ("AI OTel mapping drops AI SDK v7 cache and reasoning usage,
producing incorrect costs").
Impact
Any team on
ai@7+ Anthropic + prompt caching is under-charged by the fullcache-creation component of every request. For agent workloads (large cached system
prompts, many turns) cache creation is a large fraction of the true cost, so the
gateway-reported cost can be a small fraction of the provider list price.
Because it under-bills, it is also invisible to the usual "my bill is too high" reports,
and it silently corrupts anything downstream that trusts
providerMetadata.gateway.cost(cost dashboards, per-request budget caps, usage-based billing built on top of the gateway).
Also observed (separate, minor)
ai@6.0.159accepts aninstructionsoption but silently ignores it — in the reproduction belowthe 19.8k-token system prompt was never sent (total
input_tokenswas 14) and no warningwas emitted. Flagging in case it is unintended in that major.
Question
Is this a bug, or an intentional discount / promotion on the v4 path?
If it is intentional, it would help to have it documented — the pricing docs currently
say AI Gateway charges the provider's list price with no markup, and the Automatic
Caching docs describe Anthropic cache writes as 1.25x the base input rate — and to know
whether the v3 path will be brought in line. If it is a bug, please say whether earlier
usage will be trued up, so downstream cost tracking can be adjusted accordingly.
Reproduction
Two directories, one dependency set each, identical probe:
Run each directory once and compare
gateway.inputInferenceCostagainstinput x base + cacheWrite x (1.25x or 2x base) + cacheRead x 0.1x base.AI SDK Version
ai6.0.159,@ai-sdk/gateway3.0.96,@ai-sdk/provider3.0.8ai7.0.52,@ai-sdk/gateway4.0.41,@ai-sdk/provider4.0.5Code of Conduct