mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 11:43:57 +08:00
fix(proxy): strip leading billing header from system content (#2350)
Claude Code injects a dynamic `x-anthropic-billing-header` line at the start of `system` content. Its rotating `cch=` token was forwarded into OpenAI Responses `instructions` and Chat system messages, which broke upstream prefix prompt cache reuse — a stable ~95k-token prefix was getting re-charged on every request. Strip only the leading occurrence in both anthropic_to_openai and anthropic_to_responses; later occurrences are preserved so user-authored prompt text containing the same string is not lost.
This commit is contained in:
@@ -35,10 +35,12 @@ pub fn anthropic_to_responses(
|
||||
// system → instructions (Responses API 使用 instructions 字段)
|
||||
if let Some(system) = body.get("system") {
|
||||
let instructions = if let Some(text) = system.as_str() {
|
||||
text.to_string()
|
||||
super::transform::strip_leading_anthropic_billing_header(text).to_string()
|
||||
} else if let Some(arr) = system.as_array() {
|
||||
arr.iter()
|
||||
.filter_map(|msg| msg.get("text").and_then(|t| t.as_str()))
|
||||
.map(super::transform::strip_leading_anthropic_billing_header)
|
||||
.filter(|text| !text.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n")
|
||||
} else {
|
||||
@@ -611,6 +613,48 @@ mod tests {
|
||||
assert_eq!(result["input"].as_array().unwrap().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_strips_leading_billing_header_from_system_string() {
|
||||
let input = json!({
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1024,
|
||||
"system": "x-anthropic-billing-header: cc_version=2.1.119.47e; cc_entrypoint=sdk-cli; cch=a7754;\n\nYou are a helpful assistant.",
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_responses(input, None, false, false).unwrap();
|
||||
assert_eq!(result["instructions"], "You are a helpful assistant.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_strips_billing_header_with_crlf() {
|
||||
let input = json!({
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1024,
|
||||
"system": "x-anthropic-billing-header: cc_version=2.1.119.47e; cc_entrypoint=sdk-cli; cch=a7754;\r\n\r\nYou are a helpful assistant.",
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_responses(input, None, false, false).unwrap();
|
||||
assert_eq!(result["instructions"], "You are a helpful assistant.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_keeps_non_leading_billing_header_text() {
|
||||
let input = json!({
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1024,
|
||||
"system": "Keep this literal:\nx-anthropic-billing-header: example",
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_responses(input, None, false, false).unwrap();
|
||||
assert_eq!(
|
||||
result["instructions"],
|
||||
"Keep this literal:\nx-anthropic-billing-header: example"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_with_system_array() {
|
||||
let input = json!({
|
||||
@@ -627,6 +671,41 @@ mod tests {
|
||||
assert_eq!(result["instructions"], "Part 1\n\nPart 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_strips_billing_header_from_system_array_parts() {
|
||||
let input = json!({
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1024,
|
||||
"system": [
|
||||
{"type": "text", "text": "x-anthropic-billing-header: cc_version=2.1.119.47e; cc_entrypoint=sdk-cli; cch=a7754;\n"},
|
||||
{"type": "text", "text": "Stable prompt"}
|
||||
],
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_responses(input, None, false, false).unwrap();
|
||||
assert_eq!(result["instructions"], "Stable prompt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_preserves_prompt_after_billing_header_in_same_part() {
|
||||
let input = json!({
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 1024,
|
||||
"system": [
|
||||
{"type": "text", "text": "x-anthropic-billing-header: cc_version=2.1.119.47e; cc_entrypoint=sdk-cli; cch=a7754;\n\nStable prompt part 1"},
|
||||
{"type": "text", "text": "Stable prompt part 2"}
|
||||
],
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_responses(input, None, false, false).unwrap();
|
||||
assert_eq!(
|
||||
result["instructions"],
|
||||
"Stable prompt part 1\n\nStable prompt part 2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_responses_with_tools() {
|
||||
let input = json!({
|
||||
|
||||
Reference in New Issue
Block a user