From a9450872a326107db9b2827b31c0663d08ee735a Mon Sep 17 00:00:00 2001 From: Spherrrical Date: Mon, 30 Mar 2026 14:51:21 -0700 Subject: [PATCH] add tests for Perplexity provider handling in LLM module --- crates/brightstaff/src/handlers/llm/mod.rs | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/crates/brightstaff/src/handlers/llm/mod.rs b/crates/brightstaff/src/handlers/llm/mod.rs index aafc7fa5..b19227ae 100644 --- a/crates/brightstaff/src/handlers/llm/mod.rs +++ b/crates/brightstaff/src/handlers/llm/mod.rs @@ -782,3 +782,104 @@ async fn get_provider_info( (hermesllm::ProviderId::OpenAI, None, false) } } + +#[cfg(test)] +mod tests { + use super::{get_provider_info, get_upstream_path}; + use common::configuration::{LlmProvider, LlmProviderType}; + use common::llm_providers::LlmProviders; + use hermesllm::apis::OpenAIApi; + use hermesllm::clients::SupportedAPIsFromClient; + use std::sync::Arc; + use tokio::sync::RwLock; + + fn build_provider(name: &str, model: &str) -> LlmProvider { + LlmProvider { + name: name.to_string(), + provider_interface: LlmProviderType::OpenAI, + access_key: Some("test_key".to_string()), + model: Some(model.to_string()), + default: Some(false), + ..Default::default() + } + } + + fn providers_lock(providers: Vec) -> Arc> { + Arc::new(RwLock::new( + LlmProviders::try_from(providers).expect("test providers should be valid"), + )) + } + + #[tokio::test] + async fn test_get_provider_info_marks_perplexity_as_unversioned() { + let providers = providers_lock(vec![build_provider("perplexity/sonar-pro", "sonar-pro")]); + + let (provider_id, prefix, use_unversioned_paths) = + get_provider_info(&providers, "perplexity/sonar-pro").await; + + assert_eq!(provider_id, hermesllm::ProviderId::OpenAI); + assert_eq!(prefix, None); + assert!(use_unversioned_paths); + } + + #[tokio::test] + async fn test_get_upstream_path_for_perplexity_uses_unversioned_chat_endpoint() { + let providers = providers_lock(vec![build_provider("perplexity/sonar-pro", "sonar-pro")]); + + let upstream_path = get_upstream_path( + &providers, + "perplexity/sonar-pro", + "/v1/chat/completions", + "sonar-pro", + false, + ) + .await; + + assert_eq!(upstream_path, "/chat/completions"); + } + + #[tokio::test] + async fn test_get_upstream_path_for_non_perplexity_keeps_v1_chat_endpoint() { + let providers = providers_lock(vec![build_provider("openai/gpt-4o-mini", "gpt-4o-mini")]); + + let upstream_path = get_upstream_path( + &providers, + "openai/gpt-4o-mini", + "/v1/chat/completions", + "gpt-4o-mini", + false, + ) + .await; + + assert_eq!(upstream_path, "/v1/chat/completions"); + } + + #[tokio::test] + async fn test_perplexity_with_and_without_versioning_paths() { + let providers = providers_lock(vec![build_provider("perplexity/sonar-pro", "sonar-pro")]); + + // This is the path Plano should use for Perplexity (works). + let success_path = get_upstream_path( + &providers, + "perplexity/sonar-pro", + "/v1/chat/completions", + "sonar-pro", + false, + ) + .await; + assert_eq!(success_path, "/chat/completions"); + + // This is the generic OpenAI default path; for Perplexity this would 404. + let fail_path = SupportedAPIsFromClient::OpenAIChatCompletions(OpenAIApi::ChatCompletions) + .target_endpoint_for_provider( + &hermesllm::ProviderId::OpenAI, + "/v1/chat/completions", + "sonar-pro", + false, + None, + false, + ); + assert_eq!(fail_path, "/v1/chat/completions"); + assert_ne!(success_path, fail_path); + } +}