From 32b8b1ad74497f232560e92dea7234dc2646cb1f Mon Sep 17 00:00:00 2001 From: qihg1 Date: Thu, 22 Jan 2026 21:40:13 +0800 Subject: [PATCH] fix: filter Anthropic reserved keywords from system prompts Filter out Anthropic-specific headers like `x-anthropic-billing-header` and `x-anthropic-billing` from system prompts before sending to Copilot API. These keywords are internal to Anthropic's billing system and should not be forwarded to the Copilot backend, as they may cause unexpected behavior or errors. Fixes ericc-ch/copilot-api#174 --- src/routes/messages/non-stream-translation.ts | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/routes/messages/non-stream-translation.ts b/src/routes/messages/non-stream-translation.ts index dc41e638..61fc1a8b 100644 --- a/src/routes/messages/non-stream-translation.ts +++ b/src/routes/messages/non-stream-translation.ts @@ -71,6 +71,24 @@ function translateAnthropicMessagesToOpenAI( return [...systemMessages, ...otherMessages] } +// Anthropic reserved keywords that should not be sent to Copilot API +const ANTHROPIC_RESERVED_KEYWORDS = [ + "x-anthropic-billing-header", + "x-anthropic-billing", +] + +function filterAnthropicReservedContent(text: string): string { + let filtered = text + for (const keyword of ANTHROPIC_RESERVED_KEYWORDS) { + // Remove lines containing the reserved keyword + filtered = filtered + .split("\n") + .filter((line) => !line.includes(keyword)) + .join("\n") + } + return filtered +} + function handleSystemPrompt( system: string | Array | undefined, ): Array { @@ -78,12 +96,21 @@ function handleSystemPrompt( return [] } - if (typeof system === "string") { - return [{ role: "system", content: system }] - } else { - const systemText = system.map((block) => block.text).join("\n\n") - return [{ role: "system", content: systemText }] + let systemText: string + systemText = + typeof system === "string" ? system : ( + system.map((block) => block.text).join("\n\n") + ) + + // Filter out Anthropic reserved keywords + systemText = filterAnthropicReservedContent(systemText) + + // Only return system message if there's content left after filtering + if (systemText.trim().length === 0) { + return [] } + + return [{ role: "system", content: systemText }] } function handleUserMessage(message: AnthropicUserMessage): Array {