From fad81d6fa47bedffd0a7a254f53ab5225c1a8af6 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Thu, 12 Feb 2026 14:49:51 +0800 Subject: [PATCH] fix(proxy): strip beta=true query param when transforming to chat/completions --- src-tauri/src/proxy/forwarder.rs | 56 +++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/proxy/forwarder.rs b/src-tauri/src/proxy/forwarder.rs index 6ea8e91b5..eb10d6c11 100644 --- a/src-tauri/src/proxy/forwarder.rs +++ b/src-tauri/src/proxy/forwarder.rs @@ -565,7 +565,7 @@ impl RequestForwarder { && adapter.name() == "Claude" && endpoint.starts_with("/v1/messages") { - endpoint.replacen("/v1/messages", "/v1/chat/completions", 1) + transform_claude_messages_endpoint(endpoint) } else { endpoint.to_string() }; @@ -738,3 +738,57 @@ fn extract_error_message(error: &ProxyError) -> Option { _ => Some(error.to_string()), } } + +fn transform_claude_messages_endpoint(endpoint: &str) -> String { + let transformed = endpoint.replacen("/v1/messages", "/v1/chat/completions", 1); + + let Some((path, query)) = transformed.split_once('?') else { + return transformed; + }; + + // 转换到 chat/completions 时,显式移除 beta=true,避免把旧接口参数带到新接口。 + let filtered_params: Vec<&str> = query + .split('&') + .filter(|segment| !segment.is_empty()) + .filter(|segment| !is_beta_true_query_pair(segment)) + .collect(); + + if filtered_params.is_empty() { + path.to_string() + } else { + format!("{path}?{}", filtered_params.join("&")) + } +} + +fn is_beta_true_query_pair(segment: &str) -> bool { + let Some((key, value)) = segment.split_once('=') else { + return false; + }; + key.eq_ignore_ascii_case("beta") && value.eq_ignore_ascii_case("true") +} + +#[cfg(test)] +mod tests { + use super::transform_claude_messages_endpoint; + + #[test] + fn transform_claude_messages_endpoint_strips_beta_true_only() { + let endpoint = "/v1/messages?beta=true&foo=1"; + let transformed = transform_claude_messages_endpoint(endpoint); + assert_eq!(transformed, "/v1/chat/completions?foo=1"); + } + + #[test] + fn transform_claude_messages_endpoint_drops_empty_query_after_strip() { + let endpoint = "/v1/messages?beta=true"; + let transformed = transform_claude_messages_endpoint(endpoint); + assert_eq!(transformed, "/v1/chat/completions"); + } + + #[test] + fn transform_claude_messages_endpoint_keeps_other_query_values() { + let endpoint = "/v1/messages?beta=false&foo=1"; + let transformed = transform_claude_messages_endpoint(endpoint); + assert_eq!(transformed, "/v1/chat/completions?beta=false&foo=1"); + } +}