Limit path suffix to chat completions

This commit is contained in:
RefuseOdd
2026-06-02 17:42:33 +12:00
committed by Hunter Bown
parent d2999bb402
commit 8b0e1cc3c0
2 changed files with 61 additions and 11 deletions
+50 -8
View File
@@ -428,8 +428,14 @@ pub(super) fn api_url_with_suffix(base_url: &str, path: &str, path_suffix: Optio
if path.starts_with("beta/") {
return format!("{}/{}", unversioned_base_url(base_url), path);
}
if let Some(suffix) = path_suffix {
return format!("{}/{}", base_url.trim_end_matches('/'), suffix.trim_start_matches('/'));
if path == "chat/completions" {
if let Some(suffix) = path_suffix {
return format!(
"{}/{}",
unversioned_base_url(base_url),
suffix.trim_start_matches('/')
);
}
}
let mut versioned = versioned_base_url(base_url);
// The /beta suffix is not a real API version — it is an
@@ -703,7 +709,11 @@ impl DeepSeekClient {
model: &str,
target_language: &str,
) -> Result<String> {
let url = api_url_with_suffix(&self.base_url, "chat/completions", self.path_suffix.as_deref());
let url = api_url_with_suffix(
&self.base_url,
"chat/completions",
self.path_suffix.as_deref(),
);
let model = wire_model_for_provider(self.api_provider, model);
let mut body = serde_json::json!({
"model": model,
@@ -750,7 +760,7 @@ impl DeepSeekClient {
/// List available models from the provider.
pub async fn list_models(&self) -> Result<Vec<AvailableModel>> {
let url = api_url_with_suffix(&self.base_url, "models", self.path_suffix.as_deref());
let url = api_url(&self.base_url, "models");
let response = self.send_with_retry(|| self.http_client.get(&url)).await?;
let status = response.status();
@@ -892,7 +902,7 @@ impl DeepSeekClient {
if !should_probe {
return;
}
let health_url = api_url_with_suffix(&self.base_url, "models", self.path_suffix.as_deref());
let health_url = api_url(&self.base_url, "models");
let probe = self.http_client.get(health_url).send().await;
match probe {
Ok(resp) if resp.status().is_success() => {
@@ -1008,7 +1018,7 @@ impl LlmClient for DeepSeekClient {
}
async fn health_check(&self) -> Result<bool> {
let health_url = api_url_with_suffix(&self.base_url, "models", self.path_suffix.as_deref());
let health_url = api_url(&self.base_url, "models");
self.wait_for_rate_limit().await;
let response = self.http_client.get(health_url).send().await;
match response {
@@ -1331,7 +1341,7 @@ impl DeepSeekClient {
suffix: &str,
max_tokens: u32,
) -> anyhow::Result<String> {
let url = api_url_with_suffix(&self.base_url, "beta/completions", self.path_suffix.as_deref());
let url = api_url_with_suffix(&self.base_url, "beta/completions", None);
let model = wire_model_for_provider(self.api_provider, model);
let body = json!({
"model": model,
@@ -3483,7 +3493,7 @@ mod tests {
}
#[test]
fn api_url_with_suffix_uses_suffix_path() {
fn api_url_with_suffix_strips_version_before_chat_suffix() {
assert_eq!(
api_url_with_suffix(
"https://api.example.com/v1",
@@ -3492,6 +3502,14 @@ mod tests {
),
"https://api.example.com/chat/completions"
);
assert_eq!(
api_url_with_suffix(
"https://api.example.com/beta",
"chat/completions",
Some("/chat/completions")
),
"https://api.example.com/chat/completions"
);
}
#[test]
@@ -3506,6 +3524,30 @@ mod tests {
);
}
#[test]
fn api_url_with_suffix_ignores_suffix_for_models() {
assert_eq!(
api_url_with_suffix(
"https://api.example.com/v1",
"models",
Some("/chat/completions")
),
"https://api.example.com/v1/models"
);
}
#[test]
fn api_url_with_suffix_ignores_suffix_for_beta_paths() {
assert_eq!(
api_url_with_suffix(
"https://api.example.com/v1",
"beta/completions",
Some("/chat/completions")
),
"https://api.example.com/beta/completions"
);
}
#[test]
fn api_url_with_suffix_default_behavior_without_suffix() {
assert_eq!(
+11 -3
View File
@@ -70,7 +70,7 @@ use crate::models::{
use super::{
DeepSeekClient, ERROR_BODY_MAX_BYTES, SSE_BACKPRESSURE_HIGH_WATERMARK,
SSE_BACKPRESSURE_SLEEP_MS, SSE_MAX_LINES_PER_CHUNK, acquire_stream_buffer, api_url,
SSE_BACKPRESSURE_SLEEP_MS, SSE_MAX_LINES_PER_CHUNK, acquire_stream_buffer, api_url_with_suffix,
apply_reasoning_effort, bounded_error_text, from_api_tool_name, parse_usage,
release_stream_buffer, system_to_instructions, to_api_tool_name,
};
@@ -137,7 +137,11 @@ impl DeepSeekClient {
self.api_provider,
);
let url = api_url(&self.base_url, "chat/completions");
let url = api_url_with_suffix(
&self.base_url,
"chat/completions",
self.path_suffix.as_deref(),
);
let open_timeout = stream_open_timeout();
let response = match tokio_timeout(
open_timeout,
@@ -245,7 +249,11 @@ impl DeepSeekClient {
self.api_provider,
);
let url = api_url(&self.base_url, "chat/completions");
let url = api_url_with_suffix(
&self.base_url,
"chat/completions",
self.path_suffix.as_deref(),
);
let response = self
.send_with_retry(|| self.http_client.post(&url).json(&body))
.await?;