fix(cloudflare): pass cache control settings through AI Gateway

Cloudflare AI Gateway proxies the Anthropic Messages API, so prompt
caching headers should be forwarded just like direct Anthropic requests.
Previously resolveCacheRetention() only matched provider === 'anthropic'
and silently returned undefined for cloudflare-ai-gateway, causing
cache_control settings to be stripped.

Add 'cloudflare-ai-gateway' to the provider check so users get prompt
caching benefits when routing through Cloudflare.

Closes #46709
This commit is contained in:
杨艺韬(yangyitao) 2026-03-15 02:35:42 +00:00
parent 5e417b44e1
commit 48120cd73e
2 changed files with 41 additions and 2 deletions

View File

@ -0,0 +1,36 @@
import { describe, expect, it } from "vitest";
import { resolveCacheRetention } from "./anthropic-stream-wrappers.js";
describe("resolveCacheRetention", () => {
it("returns 'short' by default for anthropic provider", () => {
expect(resolveCacheRetention(undefined, "anthropic")).toBe("short");
});
it("returns 'short' by default for cloudflare-ai-gateway provider", () => {
expect(resolveCacheRetention(undefined, "cloudflare-ai-gateway")).toBe("short");
});
it("returns undefined for unrelated providers", () => {
expect(resolveCacheRetention(undefined, "openai")).toBeUndefined();
expect(resolveCacheRetention(undefined, "openrouter")).toBeUndefined();
});
it("returns explicit cacheRetention for cloudflare-ai-gateway", () => {
expect(resolveCacheRetention({ cacheRetention: "long" }, "cloudflare-ai-gateway")).toBe("long");
expect(resolveCacheRetention({ cacheRetention: "none" }, "cloudflare-ai-gateway")).toBe("none");
});
it("returns undefined for amazon-bedrock without explicit override", () => {
expect(resolveCacheRetention(undefined, "amazon-bedrock")).toBeUndefined();
});
it("returns explicit cacheRetention for amazon-bedrock when overridden", () => {
expect(resolveCacheRetention({ cacheRetention: "short" }, "amazon-bedrock")).toBe("short");
});
it("maps legacy cacheControlTtl values", () => {
expect(resolveCacheRetention({ cacheControlTtl: "5m" }, "anthropic")).toBe("short");
expect(resolveCacheRetention({ cacheControlTtl: "1h" }, "anthropic")).toBe("long");
expect(resolveCacheRetention({ cacheControlTtl: "5m" }, "cloudflare-ai-gateway")).toBe("short");
});
});

View File

@ -212,11 +212,14 @@ export function resolveCacheRetention(
provider: string,
): CacheRetention | undefined {
const isAnthropicDirect = provider === "anthropic";
// Cloudflare AI Gateway proxies the Anthropic Messages API and passes
// cache_control through, so treat it like direct Anthropic (#46709).
const isCloudflareAnthropicProxy = provider === "cloudflare-ai-gateway";
const hasBedrockOverride =
extraParams?.cacheRetention !== undefined || extraParams?.cacheControlTtl !== undefined;
const isAnthropicBedrock = provider === "amazon-bedrock" && hasBedrockOverride;
if (!isAnthropicDirect && !isAnthropicBedrock) {
if (!isAnthropicDirect && !isCloudflareAnthropicProxy && !isAnthropicBedrock) {
return undefined;
}
@ -233,7 +236,7 @@ export function resolveCacheRetention(
return "long";
}
return isAnthropicDirect ? "short" : undefined;
return isAnthropicDirect || isCloudflareAnthropicProxy ? "short" : undefined;
}
export function resolveAnthropicBetas(