From be2f7cb3e57b2f50c8880cacb4c2e60631baafd5 Mon Sep 17 00:00:00 2001 From: Randi <55005611+rdself@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:17:21 -0400 Subject: [PATCH] fix(cc-compatible): keep cache ttl ordering valid (#948) --- open-sse/services/claudeCodeCompatible.ts | 35 +++++++++++-------- tests/unit/cc-compatible-provider.test.mjs | 39 +++++++++++++++++++--- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/open-sse/services/claudeCodeCompatible.ts b/open-sse/services/claudeCodeCompatible.ts index c900bcf35a..85c02db5e5 100644 --- a/open-sse/services/claudeCodeCompatible.ts +++ b/open-sse/services/claudeCodeCompatible.ts @@ -397,8 +397,14 @@ function buildClaudeCodeCompatibleSystemBlocks({ }) { const customSystemBlocks = Array.isArray(systemBlocks) && systemBlocks.length > 0 - ? systemBlocks + ? systemBlocks.map((block) => ({ ...block })) : extractCustomSystemBlocks(messages); + const useLongSystemTtl = + !preserveCacheControl || + customSystemBlocks.some((block) => readCacheControlTtl(block) === "1h"); + const systemCacheControl = useLongSystemTtl + ? { type: "ephemeral", ttl: "1h" } + : { type: "ephemeral" }; const dateText = formatDate(now); const blocks: Array> = [ @@ -409,17 +415,21 @@ function buildClaudeCodeCompatibleSystemBlocks({ { type: "text", text: "You are a Claude agent, built on Anthropic's Claude Agent SDK.", - cache_control: { type: "ephemeral" }, + cache_control: { ...systemCacheControl }, }, { type: "text", text: `You are Claude Code, Anthropic's official CLI for Claude.\n\nCWD: ${cwd}\nDate: ${dateText}`, - cache_control: { type: "ephemeral" }, + cache_control: { ...systemCacheControl }, }, ]; for (const systemBlock of customSystemBlocks) { - blocks.push(systemBlock); + const preparedBlock = { ...systemBlock }; + if (!preserveCacheControl || useLongSystemTtl) { + preparedBlock.cache_control = { ...systemCacheControl }; + } + blocks.push(preparedBlock); } if ( @@ -427,8 +437,8 @@ function buildClaudeCodeCompatibleSystemBlocks({ customSystemBlocks.length > 0 && !customSystemBlocks.some((block) => hasCacheControl(block)) ) { - const lastCustomSystemBlock = customSystemBlocks[customSystemBlocks.length - 1]; - lastCustomSystemBlock.cache_control = { type: "ephemeral", ttl: "1h" }; + const lastCustomSystemBlock = blocks[blocks.length - 1]; + lastCustomSystemBlock.cache_control = { ...systemCacheControl }; } return blocks; @@ -650,7 +660,7 @@ function convertClaudeCodeCompatibleClaudeMessage( function extractCustomSystemBlocks(messages: MessageLike[] | undefined) { if (!Array.isArray(messages)) return []; - const blocks = messages + return messages .filter((message) => { const role = String(message?.role || "").toLowerCase(); return role === "system" || role === "developer"; @@ -660,14 +670,7 @@ function extractCustomSystemBlocks(messages: MessageLike[] | undefined) { .map((text) => ({ type: "text", text, - cache_control: { type: "ephemeral" }, })); - - if (blocks.length > 0) { - blocks[blocks.length - 1].cache_control = { type: "ephemeral", ttl: "1h" }; - } - - return blocks; } function applyClaudeCodeCompatibleMessageCacheStrategy( @@ -762,6 +765,10 @@ function hasCacheControl(value: unknown) { return !!readRecord(value)?.cache_control && typeof readRecord(value)?.cache_control === "object"; } +function readCacheControlTtl(value: unknown) { + return toNonEmptyString(readRecord(readRecord(value)?.cache_control)?.ttl); +} + function findLastCacheableToolIndex(tools: Array>) { for (let i = tools.length - 1; i >= 0; i--) { if (!tools[i].defer_loading) { diff --git a/tests/unit/cc-compatible-provider.test.mjs b/tests/unit/cc-compatible-provider.test.mjs index 4060f825d5..961905a648 100644 --- a/tests/unit/cc-compatible-provider.test.mjs +++ b/tests/unit/cc-compatible-provider.test.mjs @@ -109,6 +109,9 @@ test("buildClaudeCodeCompatibleRequest keeps prior role history while dropping t assert.deepEqual(payload.messages[2].content.at(-1).cache_control, { type: "ephemeral" }); assert.equal(payload.system.length, 4); assert.equal(payload.system.at(-1).text, "sys"); + assert.deepEqual(payload.system[1].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[2].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[3].cache_control, { type: "ephemeral", ttl: "1h" }); assert.equal(payload.tools.length, 1); const { cache_control, ...toolWithoutCacheControl } = payload.tools[0]; assert.deepEqual(toolWithoutCacheControl, { @@ -230,9 +233,38 @@ test("buildClaudeCodeCompatibleRequest supplements missing Claude cache markers assert.deepEqual(payload.messages[0].content[0].cache_control, { type: "ephemeral" }); assert.deepEqual(payload.messages[1].content[0].cache_control, { type: "ephemeral" }); assert.deepEqual(payload.messages[2].content[0].cache_control, { type: "ephemeral" }); + assert.deepEqual(payload.system.at(-1).cache_control, { type: "ephemeral" }); assert.deepEqual(payload.tools[0].cache_control, { type: "ephemeral", ttl: "1h" }); }); +test("buildClaudeCodeCompatibleRequest upgrades built-in system cache markers when preserved system uses 1h", () => { + const payload = buildClaudeCodeCompatibleRequest({ + sourceBody: { + max_tokens: 64, + }, + normalizedBody: { + max_tokens: 64, + messages: [{ role: "user", content: "fallback" }], + }, + claudeBody: { + system: [ + { type: "text", text: "prefix", cache_control: { type: "ephemeral" } }, + { type: "text", text: "stable", cache_control: { type: "ephemeral", ttl: "1h" } }, + ], + messages: [{ role: "user", content: [{ type: "text", text: "u1" }] }], + tools: [], + }, + model: "claude-sonnet-4-6", + sessionId: "session-preserve-system-upgrade", + preserveCacheControl: true, + }); + + assert.deepEqual(payload.system[1].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[2].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[3].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[4].cache_control, { type: "ephemeral", ttl: "1h" }); +}); + test("buildClaudeCodeCompatibleRequest marks final user turn and 1h system cache in non-preserve mode", () => { const largeUserPrompt = Array.from( { length: 200 }, @@ -257,10 +289,9 @@ test("buildClaudeCodeCompatibleRequest marks final user turn and 1h system cache preserveCacheControl: false, }); - assert.deepEqual(payload.system.at(-1).cache_control, { - type: "ephemeral", - ttl: "1h", - }); + assert.deepEqual(payload.system[1].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[2].cache_control, { type: "ephemeral", ttl: "1h" }); + assert.deepEqual(payload.system[3].cache_control, { type: "ephemeral", ttl: "1h" }); assert.deepEqual(payload.messages[0].content[0].cache_control, { type: "ephemeral" }); assert.deepEqual(payload.messages[1].content[0].cache_control, { type: "ephemeral" }); assert.deepEqual(payload.messages[2].content[0].cache_control, { type: "ephemeral" });