pub fn join_api_path(base: &str, path: &str) -> String {
let base = strip_chat_endpoint(base.trim().trim_end_matches('#').trim_end_matches('/'));
format!("{base}/{path}")
}
pub fn join_chat_endpoint(base: &str, path: &str) -> String {
let probe = base.trim().trim_end_matches('#').trim_end_matches('/');
if probe.ends_with(path) {
return probe.to_string();
}
if path == "messages" {
return join_api_path(&anthropic_base_url(base), path);
}
join_api_path(base, path)
}
pub fn anthropic_base_url(base: &str) -> String {
let t = base.trim();
let pinned = t.ends_with('#');
let b = strip_chat_endpoint(t.trim_end_matches('#').trim_end_matches('/'));
if pinned || b.is_empty() || ends_with_version_segment(b) {
return b.to_string();
}
format!("{b}/v1")
}
fn strip_chat_endpoint(base: &str) -> &str {
for suffix in ["chat/completions", "messages"] {
if let Some(rest) = base.strip_suffix(suffix) {
return rest.trim_end_matches('/');
}
}
base
}
pub fn ends_with_version_segment(base: &str) -> bool {
base.trim()
.trim_end_matches('/')
.rsplit('/')
.next()
.and_then(|seg| seg.strip_prefix('v'))
.is_some_and(|rest| !rest.is_empty() && rest.bytes().all(|b| b.is_ascii_digit()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn join_api_path_never_infers_version_segment() {
assert_eq!(
join_api_path("https://api.deepseek.com", "chat/completions"),
"https://api.deepseek.com/chat/completions"
);
assert_eq!(
join_api_path("https://api.deepseek.com/v1", "chat/completions"),
"https://api.deepseek.com/v1/chat/completions"
);
assert_eq!(
join_api_path("https://open.bigmodel.cn/api/paas/v4", "chat/completions"),
"https://open.bigmodel.cn/api/paas/v4/chat/completions"
);
assert_eq!(
join_api_path(
"https://generativelanguage.googleapis.com/v1beta/openai",
"chat/completions"
),
"https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
);
}
#[test]
fn join_api_path_trims_slash_and_legacy_hash() {
assert_eq!(
join_api_path("https://api.deepseek.com/v1/", "models"),
"https://api.deepseek.com/v1/models"
);
assert_eq!(
join_api_path(
"https://generativelanguage.googleapis.com/v1beta/openai#",
"models"
),
"https://generativelanguage.googleapis.com/v1beta/openai/models"
);
assert_eq!(
join_api_path(" https://api.deepseek.com/v1 ", "models"),
"https://api.deepseek.com/v1/models"
);
}
#[test]
fn join_chat_endpoint_accepts_full_endpoint() {
let full = "https://proxy.example.com/v1/chat/completions";
assert_eq!(join_chat_endpoint(full, "chat/completions"), full);
assert_eq!(
join_api_path(full, "models"),
"https://proxy.example.com/v1/models"
);
let anth = "https://proxy.example.com/v1/messages";
assert_eq!(join_chat_endpoint(anth, "messages"), anth);
}
#[test]
fn anthropic_base_gets_v1_when_missing() {
for (raw, want) in [
(
"https://cc.example.top:8443",
"https://cc.example.top:8443/v1",
),
("https://api.anthropic.com/", "https://api.anthropic.com/v1"),
(
"https://api.deepseek.com/anthropic",
"https://api.deepseek.com/anthropic/v1",
),
(
"https://api.anthropic.com/v1",
"https://api.anthropic.com/v1",
),
(
"https://proxy.example.com/v1/messages",
"https://proxy.example.com/v1",
),
(
"https://odd.gateway.com/raw#",
"https://odd.gateway.com/raw",
),
] {
assert_eq!(anthropic_base_url(raw), want, "raw={raw}");
}
assert_eq!(
join_chat_endpoint("https://cc.example.top:8443", "messages"),
"https://cc.example.top:8443/v1/messages"
);
let once = anthropic_base_url("https://cc.example.top:8443");
assert_eq!(anthropic_base_url(&once), once);
}
#[test]
fn openai_side_still_never_infers() {
assert_eq!(
join_chat_endpoint("https://api.deepseek.com", "chat/completions"),
"https://api.deepseek.com/chat/completions"
);
}
#[test]
fn version_segment_detection() {
assert!(ends_with_version_segment("https://api.deepseek.com/v1"));
assert!(ends_with_version_segment(
"https://open.bigmodel.cn/api/paas/v4"
));
assert!(ends_with_version_segment("https://api.deepseek.com/v1/"));
assert!(!ends_with_version_segment("https://api.deepseek.com"));
assert!(!ends_with_version_segment("https://v4.example.com"));
assert!(!ends_with_version_segment("https://x.com/v1beta/openai"));
}
}