fix(provider): split partial model fetch warnings from errors

This commit is contained in:
zhefox
2026-05-26 17:45:06 +08:00
parent aa409a8a9c
commit 1173a4d9d5
14 changed files with 171 additions and 48 deletions
+41 -7
View File
@@ -22,7 +22,7 @@ use aether_provider_transport::{
use async_trait::async_trait;
use serde_json::{json, Value};
use crate::build_models_fetch_url;
use crate::{build_models_fetch_url, deepseek_anthropic_models_fetch_uses_openai_auth};
const OPENAI_RESPONSES_USER_AGENT: &str = "openai-codex/1.0";
const CLAUDE_CLI_USER_AGENT: &str = "claude-code/1.0.1";
@@ -98,19 +98,29 @@ pub async fn build_standard_models_fetch_execution_plan(
let provider_type = transport.provider.provider_type.trim().to_ascii_lowercase();
let is_codex_openai_models_fetch =
provider_type == "codex" && api_format.starts_with("openai:");
let is_deepseek_anthropic_models_fetch = api_format.starts_with("claude:")
&& deepseek_anthropic_models_fetch_uses_openai_auth(&transport.endpoint.base_url);
let mut headers = standard_models_fetch_headers(&api_format, &provider_type);
if is_codex_openai_models_fetch {
headers.insert("accept".to_string(), "application/json".to_string());
}
if is_deepseek_anthropic_models_fetch {
headers.remove("anthropic-version");
headers.insert("accept".to_string(), "application/json".to_string());
}
let mut protected_headers = Vec::<String>::new();
if api_format.starts_with("openai:") || api_format.starts_with("claude:") {
let (auth_header_name, auth_header_value) =
resolve_standard_header_auth(runtime, transport)
let resolved_auth = if is_deepseek_anthropic_models_fetch {
resolve_oauth_header_auth(runtime, transport)
.await?
.ok_or_else(|| {
"Rust models fetch auth resolution is not supported for this key".to_string()
})?;
.or_else(|| resolve_local_openai_bearer_auth(transport))
} else {
resolve_standard_header_auth(runtime, transport).await?
};
let (auth_header_name, auth_header_value) = resolved_auth.ok_or_else(|| {
"Rust models fetch auth resolution is not supported for this key".to_string()
})?;
insert_non_empty_auth_header(
&mut headers,
&mut protected_headers,
@@ -590,7 +600,9 @@ fn build_standard_models_fetch_url(
)
.ok_or_else(|| "Rust models fetch does not support this provider format yet".to_string())?;
if api_format.starts_with("claude:") {
if api_format.starts_with("claude:")
&& !deepseek_anthropic_models_fetch_uses_openai_auth(&transport.endpoint.base_url)
{
url = append_query_param(url, "limit", "100");
if let Some(after_id) = after_id.map(str::trim).filter(|value| !value.is_empty()) {
url = append_query_param(url, "after_id", after_id);
@@ -914,6 +926,28 @@ mod tests {
);
}
#[tokio::test]
async fn builds_deepseek_anthropic_models_fetch_plan_with_openai_models_endpoint() {
let runtime = TestRuntime {
oauth_auth: None,
proxy: None,
};
let mut transport = sample_transport("custom", "claude:messages", "api_key");
transport.endpoint.base_url = "https://api.deepseek.com/anthropic".to_string();
transport.key.decrypted_auth_config = None;
let plan = build_models_fetch_execution_plan(&runtime, &transport)
.await
.expect("plan");
assert_eq!(plan.url, "https://api.deepseek.com/models");
assert_eq!(
plan.headers.get("authorization").map(String::as_str),
Some("Bearer secret")
);
assert!(!plan.headers.contains_key("x-api-key"));
assert!(!plan.headers.contains_key("anthropic-version"));
}
#[tokio::test]
async fn builds_gemini_models_fetch_plan_with_browser_headers_and_query_auth() {
let runtime = TestRuntime {