mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 11:43:57 +08:00
refactor(proxy): remove beta query handling
This commit is contained in:
@@ -1170,21 +1170,6 @@ fn split_endpoint_and_query(endpoint: &str) -> (&str, Option<&str>) {
|
|||||||
.map_or((endpoint, None), |(path, query)| (path, Some(query)))
|
.map_or((endpoint, None), |(path, query)| (path, Some(query)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_beta_query(query: Option<&str>) -> Option<String> {
|
|
||||||
let filtered = query.map(|query| {
|
|
||||||
query
|
|
||||||
.split('&')
|
|
||||||
.filter(|pair| !pair.is_empty() && !pair.starts_with("beta="))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("&")
|
|
||||||
});
|
|
||||||
|
|
||||||
match filtered.as_deref() {
|
|
||||||
Some("") | None => None,
|
|
||||||
Some(_) => filtered,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_claude_messages_path(path: &str) -> bool {
|
fn is_claude_messages_path(path: &str) -> bool {
|
||||||
matches!(path, "/v1/messages" | "/claude/v1/messages")
|
matches!(path, "/v1/messages" | "/claude/v1/messages")
|
||||||
}
|
}
|
||||||
@@ -1195,14 +1180,10 @@ fn rewrite_claude_transform_endpoint(
|
|||||||
is_copilot: bool,
|
is_copilot: bool,
|
||||||
) -> (String, Option<String>) {
|
) -> (String, Option<String>) {
|
||||||
let (path, query) = split_endpoint_and_query(endpoint);
|
let (path, query) = split_endpoint_and_query(endpoint);
|
||||||
let filtered_query = if is_claude_messages_path(path) {
|
let passthrough_query = query.map(ToString::to_string);
|
||||||
filter_beta_query(query)
|
|
||||||
} else {
|
|
||||||
query.map(ToString::to_string)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !is_claude_messages_path(path) {
|
if !is_claude_messages_path(path) {
|
||||||
return (endpoint.to_string(), filtered_query);
|
return (endpoint.to_string(), passthrough_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_path = if is_copilot {
|
let target_path = if is_copilot {
|
||||||
@@ -1213,12 +1194,12 @@ fn rewrite_claude_transform_endpoint(
|
|||||||
"/v1/chat/completions"
|
"/v1/chat/completions"
|
||||||
};
|
};
|
||||||
|
|
||||||
let rewritten = match filtered_query.as_deref() {
|
let rewritten = match passthrough_query.as_deref() {
|
||||||
Some(query) if !query.is_empty() => format!("{target_path}?{query}"),
|
Some(query) if !query.is_empty() => format!("{target_path}?{query}"),
|
||||||
_ => target_path.to_string(),
|
_ => target_path.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
(rewritten, filtered_query)
|
(rewritten, passthrough_query)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_query_to_full_url(base_url: &str, query: Option<&str>) -> String {
|
fn append_query_to_full_url(base_url: &str, query: Option<&str>) -> String {
|
||||||
@@ -1343,9 +1324,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rewrite_claude_transform_endpoint_strips_beta_for_chat_completions() {
|
fn rewrite_claude_transform_endpoint_preserves_query_for_chat_completions() {
|
||||||
let (endpoint, passthrough_query) = rewrite_claude_transform_endpoint(
|
let (endpoint, passthrough_query) = rewrite_claude_transform_endpoint(
|
||||||
"/v1/messages?beta=true&foo=bar",
|
"/v1/messages?foo=bar",
|
||||||
"openai_chat",
|
"openai_chat",
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@@ -1355,9 +1336,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rewrite_claude_transform_endpoint_strips_only_beta_for_responses() {
|
fn rewrite_claude_transform_endpoint_preserves_query_for_responses() {
|
||||||
let (endpoint, passthrough_query) = rewrite_claude_transform_endpoint(
|
let (endpoint, passthrough_query) = rewrite_claude_transform_endpoint(
|
||||||
"/claude/v1/messages?beta=true&x-id=1",
|
"/claude/v1/messages?x-id=1",
|
||||||
"openai_responses",
|
"openai_responses",
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@@ -1369,7 +1350,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rewrite_claude_transform_endpoint_uses_copilot_path() {
|
fn rewrite_claude_transform_endpoint_uses_copilot_path() {
|
||||||
let (endpoint, passthrough_query) =
|
let (endpoint, passthrough_query) =
|
||||||
rewrite_claude_transform_endpoint("/v1/messages?beta=true&x-id=1", "anthropic", true);
|
rewrite_claude_transform_endpoint("/v1/messages?x-id=1", "anthropic", true);
|
||||||
|
|
||||||
assert_eq!(endpoint, "/chat/completions?x-id=1");
|
assert_eq!(endpoint, "/chat/completions?x-id=1");
|
||||||
assert_eq!(passthrough_query.as_deref(), Some("x-id=1"));
|
assert_eq!(passthrough_query.as_deref(), Some("x-id=1"));
|
||||||
|
|||||||
@@ -299,8 +299,6 @@ impl ProviderAdapter for ClaudeAdapter {
|
|||||||
// 现在 OpenRouter 已推出 Claude Code 兼容接口,因此默认直接透传 endpoint。
|
// 现在 OpenRouter 已推出 Claude Code 兼容接口,因此默认直接透传 endpoint。
|
||||||
// 如需回退旧逻辑,可在 forwarder 中根据 needs_transform 改写 endpoint。
|
// 如需回退旧逻辑,可在 forwarder 中根据 needs_transform 改写 endpoint。
|
||||||
//
|
//
|
||||||
// `?beta=true` 由客户端请求决定,代理不再硬编码追加。
|
|
||||||
|
|
||||||
let mut base = format!(
|
let mut base = format!(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
base_url.trim_end_matches('/'),
|
base_url.trim_end_matches('/'),
|
||||||
@@ -312,24 +310,7 @@ impl ProviderAdapter for ClaudeAdapter {
|
|||||||
base = base.replace("/v1/v1", "/v1");
|
base = base.replace("/v1/v1", "/v1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitHub Copilot 不需要 ?beta=true 参数
|
base
|
||||||
if base_url.contains("githubcopilot.com") {
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为 Claude 原生 /v1/messages 端点添加 ?beta=true 参数
|
|
||||||
// 这是某些上游服务(如 DuckCoding)验证请求来源的关键参数
|
|
||||||
// 注意:不要为 OpenAI Chat Completions (/v1/chat/completions) 添加此参数
|
|
||||||
// 当 apiFormat="openai_chat" 时,请求会转发到 /v1/chat/completions,
|
|
||||||
// 但该端点是 OpenAI 标准,不支持 ?beta=true 参数
|
|
||||||
if endpoint.contains("/v1/messages")
|
|
||||||
&& !endpoint.contains("/v1/chat/completions")
|
|
||||||
&& !endpoint.contains('?')
|
|
||||||
{
|
|
||||||
format!("{base}?beta=true")
|
|
||||||
} else {
|
|
||||||
base
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_auth_headers(&self, request: RequestBuilder, auth: &AuthInfo) -> RequestBuilder {
|
fn add_auth_headers(&self, request: RequestBuilder, auth: &AuthInfo) -> RequestBuilder {
|
||||||
@@ -578,14 +559,14 @@ mod tests {
|
|||||||
fn test_build_url_anthropic() {
|
fn test_build_url_anthropic() {
|
||||||
let adapter = ClaudeAdapter::new();
|
let adapter = ClaudeAdapter::new();
|
||||||
let url = adapter.build_url("https://api.anthropic.com", "/v1/messages");
|
let url = adapter.build_url("https://api.anthropic.com", "/v1/messages");
|
||||||
assert_eq!(url, "https://api.anthropic.com/v1/messages?beta=true");
|
assert_eq!(url, "https://api.anthropic.com/v1/messages");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_url_openrouter() {
|
fn test_build_url_openrouter() {
|
||||||
let adapter = ClaudeAdapter::new();
|
let adapter = ClaudeAdapter::new();
|
||||||
let url = adapter.build_url("https://openrouter.ai/api", "/v1/messages");
|
let url = adapter.build_url("https://openrouter.ai/api", "/v1/messages");
|
||||||
assert_eq!(url, "https://openrouter.ai/api/v1/messages?beta=true");
|
assert_eq!(url, "https://openrouter.ai/api/v1/messages");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -612,8 +593,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_build_url_no_beta_for_openai_chat_completions() {
|
fn test_build_url_no_beta_for_openai_chat_completions() {
|
||||||
let adapter = ClaudeAdapter::new();
|
let adapter = ClaudeAdapter::new();
|
||||||
// OpenAI Chat Completions 端点不添加 ?beta=true
|
|
||||||
// 这是 Nvidia 等 apiFormat="openai_chat" 供应商使用的端点
|
|
||||||
let url = adapter.build_url("https://integrate.api.nvidia.com", "/v1/chat/completions");
|
let url = adapter.build_url("https://integrate.api.nvidia.com", "/v1/chat/completions");
|
||||||
assert_eq!(url, "https://integrate.api.nvidia.com/v1/chat/completions");
|
assert_eq!(url, "https://integrate.api.nvidia.com/v1/chat/completions");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -738,9 +738,9 @@ impl StreamCheckService {
|
|||||||
format!("{base}/v1/chat/completions")
|
format!("{base}/v1/chat/completions")
|
||||||
}
|
}
|
||||||
} else if base.ends_with("/v1") {
|
} else if base.ends_with("/v1") {
|
||||||
format!("{base}/messages?beta=true")
|
format!("{base}/messages")
|
||||||
} else {
|
} else {
|
||||||
format!("{base}/v1/messages?beta=true")
|
format!("{base}/v1/messages")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -903,6 +903,6 @@ mod tests {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(url, "https://api.anthropic.com/v1/messages?beta=true");
|
assert_eq!(url, "https://api.anthropic.com/v1/messages");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user