mirror of
https://github.com/katanemo/plano.git
synced 2026-06-17 15:25:17 +02:00
feat(providers): add Qianfan support
This commit is contained in:
parent
938f9c4bdf
commit
e3911a2f43
9 changed files with 147 additions and 0 deletions
|
|
@ -372,6 +372,8 @@ pub enum LlmProviderType {
|
|||
OpenAI,
|
||||
#[serde(rename = "xiaomi")]
|
||||
Xiaomi,
|
||||
#[serde(rename = "qianfan")]
|
||||
Qianfan,
|
||||
#[serde(rename = "gemini")]
|
||||
Gemini,
|
||||
#[serde(rename = "xai")]
|
||||
|
|
@ -412,6 +414,7 @@ impl Display for LlmProviderType {
|
|||
LlmProviderType::Mistral => write!(f, "mistral"),
|
||||
LlmProviderType::OpenAI => write!(f, "openai"),
|
||||
LlmProviderType::Xiaomi => write!(f, "xiaomi"),
|
||||
LlmProviderType::Qianfan => write!(f, "qianfan"),
|
||||
LlmProviderType::XAI => write!(f, "xai"),
|
||||
LlmProviderType::TogetherAI => write!(f, "together_ai"),
|
||||
LlmProviderType::AzureOpenAI => write!(f, "azure_openai"),
|
||||
|
|
@ -783,6 +786,15 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_llm_provider_type_qianfan_roundtrip() {
|
||||
let parsed: LlmProviderType =
|
||||
serde_yaml::from_str("qianfan").expect("variant should deserialize");
|
||||
assert_eq!(parsed, LlmProviderType::Qianfan);
|
||||
assert_eq!(parsed.to_string(), "qianfan");
|
||||
assert_eq!(parsed.to_provider_id(), hermesllm::ProviderId::Qianfan);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_overrides_disable_signals_default_none() {
|
||||
let overrides = super::Overrides::default();
|
||||
|
|
|
|||
|
|
@ -133,6 +133,13 @@ impl SupportedAPIsFromClient {
|
|||
build_endpoint("/v1", endpoint_suffix)
|
||||
}
|
||||
}
|
||||
ProviderId::Qianfan => {
|
||||
if request_path.starts_with("/v1/") {
|
||||
build_endpoint("/v2", endpoint_suffix)
|
||||
} else {
|
||||
build_endpoint("/v1", endpoint_suffix)
|
||||
}
|
||||
}
|
||||
ProviderId::AzureOpenAI => {
|
||||
if request_path.starts_with("/v1/") {
|
||||
let suffix = endpoint_suffix.trim_start_matches('/');
|
||||
|
|
@ -400,6 +407,19 @@ mod tests {
|
|||
"/compatible-mode/v1/chat/completions"
|
||||
);
|
||||
|
||||
// Test Qianfan provider
|
||||
assert_eq!(
|
||||
api.target_endpoint_for_provider(
|
||||
&ProviderId::Qianfan,
|
||||
"/v1/chat/completions",
|
||||
"ernie-4.0-turbo-8k",
|
||||
false,
|
||||
None,
|
||||
false
|
||||
),
|
||||
"/v2/chat/completions"
|
||||
);
|
||||
|
||||
// Test Azure OpenAI provider
|
||||
assert_eq!(
|
||||
api.target_endpoint_for_provider(
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ fn load_provider_models() -> &'static HashMap<String, Vec<String>> {
|
|||
pub enum ProviderId {
|
||||
OpenAI,
|
||||
Xiaomi,
|
||||
Qianfan,
|
||||
Mistral,
|
||||
Deepseek,
|
||||
Groq,
|
||||
|
|
@ -57,6 +58,8 @@ impl TryFrom<&str> for ProviderId {
|
|||
match value.to_lowercase().as_str() {
|
||||
"openai" => Ok(ProviderId::OpenAI),
|
||||
"xiaomi" => Ok(ProviderId::Xiaomi),
|
||||
"qianfan" => Ok(ProviderId::Qianfan),
|
||||
"baidu" => Ok(ProviderId::Qianfan), // alias
|
||||
"mistral" => Ok(ProviderId::Mistral),
|
||||
"deepseek" => Ok(ProviderId::Deepseek),
|
||||
"groq" => Ok(ProviderId::Groq),
|
||||
|
|
@ -97,6 +100,7 @@ impl ProviderId {
|
|||
ProviderId::Gemini => "google",
|
||||
ProviderId::OpenAI => "openai",
|
||||
ProviderId::Xiaomi => "xiaomi",
|
||||
ProviderId::Qianfan => "qianfan",
|
||||
ProviderId::Anthropic => "anthropic",
|
||||
ProviderId::Mistral => "mistralai",
|
||||
ProviderId::Deepseek => "deepseek",
|
||||
|
|
@ -159,6 +163,7 @@ impl ProviderId {
|
|||
(
|
||||
ProviderId::OpenAI
|
||||
| ProviderId::Xiaomi
|
||||
| ProviderId::Qianfan
|
||||
| ProviderId::Groq
|
||||
| ProviderId::Mistral
|
||||
| ProviderId::Deepseek
|
||||
|
|
@ -181,6 +186,7 @@ impl ProviderId {
|
|||
(
|
||||
ProviderId::OpenAI
|
||||
| ProviderId::Xiaomi
|
||||
| ProviderId::Qianfan
|
||||
| ProviderId::Groq
|
||||
| ProviderId::Mistral
|
||||
| ProviderId::Deepseek
|
||||
|
|
@ -248,6 +254,7 @@ impl Display for ProviderId {
|
|||
match self {
|
||||
ProviderId::OpenAI => write!(f, "OpenAI"),
|
||||
ProviderId::Xiaomi => write!(f, "xiaomi"),
|
||||
ProviderId::Qianfan => write!(f, "qianfan"),
|
||||
ProviderId::Mistral => write!(f, "Mistral"),
|
||||
ProviderId::Deepseek => write!(f, "Deepseek"),
|
||||
ProviderId::Groq => write!(f, "Groq"),
|
||||
|
|
@ -380,6 +387,13 @@ mod tests {
|
|||
assert!(ProviderId::try_from("open_router").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_qianfan_parsing_and_display() {
|
||||
assert_eq!(ProviderId::try_from("qianfan"), Ok(ProviderId::Qianfan));
|
||||
assert_eq!(ProviderId::try_from("baidu"), Ok(ProviderId::Qianfan));
|
||||
assert_eq!(ProviderId::Qianfan.to_string(), "qianfan");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vercel_compatible_api() {
|
||||
use crate::clients::endpoints::{SupportedAPIsFromClient, SupportedUpstreamAPIs};
|
||||
|
|
@ -436,6 +450,34 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_qianfan_compatible_api() {
|
||||
use crate::clients::endpoints::{SupportedAPIsFromClient, SupportedUpstreamAPIs};
|
||||
|
||||
let openai_client =
|
||||
SupportedAPIsFromClient::OpenAIChatCompletions(OpenAIApi::ChatCompletions);
|
||||
let upstream = ProviderId::Qianfan.compatible_api_for_client(&openai_client, false);
|
||||
assert!(
|
||||
matches!(upstream, SupportedUpstreamAPIs::OpenAIChatCompletions(_)),
|
||||
"Qianfan should map OpenAI client to OpenAIChatCompletions upstream"
|
||||
);
|
||||
|
||||
let anthropic_client =
|
||||
SupportedAPIsFromClient::AnthropicMessagesAPI(AnthropicApi::Messages);
|
||||
let upstream = ProviderId::Qianfan.compatible_api_for_client(&anthropic_client, false);
|
||||
assert!(
|
||||
matches!(upstream, SupportedUpstreamAPIs::OpenAIChatCompletions(_)),
|
||||
"Qianfan should translate Anthropic client to OpenAIChatCompletions upstream"
|
||||
);
|
||||
|
||||
let responses_client = SupportedAPIsFromClient::OpenAIResponsesAPI(OpenAIApi::Responses);
|
||||
let upstream = ProviderId::Qianfan.compatible_api_for_client(&responses_client, false);
|
||||
assert!(
|
||||
matches!(upstream, SupportedUpstreamAPIs::OpenAIChatCompletions(_)),
|
||||
"Qianfan should translate Responses API client to OpenAIChatCompletions upstream"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vercel_and_openrouter_empty_models() {
|
||||
assert!(ProviderId::Vercel.models().is_empty());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue