From 111a31e4db09f7ff8e34183a61b6245d45d15f5e Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 2 Feb 2026 19:19:12 +0100 Subject: [PATCH] fix(ai): apply cache_control to string user messages --- packages/ai/src/providers/anthropic.ts | 9 +++++++- packages/ai/test/cache-retention.test.ts | 28 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index c2ce38b4..dd1ab70b 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -674,7 +674,6 @@ function convertMessages( if (cacheControl && params.length > 0) { const lastMessage = params[params.length - 1]; if (lastMessage.role === "user") { - // Add cache control to the last content block if (Array.isArray(lastMessage.content)) { const lastBlock = lastMessage.content[lastMessage.content.length - 1]; if ( @@ -683,6 +682,14 @@ function convertMessages( ) { (lastBlock as any).cache_control = cacheControl; } + } else if (typeof lastMessage.content === "string") { + lastMessage.content = [ + { + type: "text", + text: lastMessage.content, + cache_control: cacheControl, + }, + ] as any; } } } diff --git a/packages/ai/test/cache-retention.test.ts b/packages/ai/test/cache-retention.test.ts index 8fdcadb9..530679c6 100644 --- a/packages/ai/test/cache-retention.test.ts +++ b/packages/ai/test/cache-retention.test.ts @@ -139,6 +139,34 @@ describe("Cache Retention (PI_CACHE_RETENTION)", () => { expect(capturedPayload.system[0].cache_control).toBeUndefined(); }); + it("should add cache_control to string user messages", async () => { + const baseModel = getModel("anthropic", "claude-3-5-haiku-20241022"); + let capturedPayload: any = null; + + const { streamAnthropic } = await import("../src/providers/anthropic.js"); + + try { + const s = streamAnthropic(baseModel, context, { + apiKey: "fake-key", + onPayload: (payload) => { + capturedPayload = payload; + }, + }); + + for await (const event of s) { + if (event.type === "error") break; + } + } catch { + // Expected to fail + } + + expect(capturedPayload).not.toBeNull(); + const lastMessage = capturedPayload.messages[capturedPayload.messages.length - 1]; + expect(Array.isArray(lastMessage.content)).toBe(true); + const lastBlock = lastMessage.content[lastMessage.content.length - 1]; + expect(lastBlock.cache_control).toEqual({ type: "ephemeral" }); + }); + it("should set 1h cache TTL when cacheRetention is long", async () => { const baseModel = getModel("anthropic", "claude-3-5-haiku-20241022"); let capturedPayload: any = null;