From 3c0d67e17d8b7a1f33bc4535498fb3706ce98ac1 Mon Sep 17 00:00:00 2001 From: Raushankumar0720 Date: Thu, 24 Sep 2026 13:34:03 +0530 Subject: [PATCH] refactor(llms): remove redundant snowflake normalization and expand url test coverage --- litellm/llms/snowflake/chat/transformation.py | 2 - .../snowflake/embedding/transformation.py | 2 - .../llms/test_provider_url_trailing_slash.py | 218 ++++++++++++++---- 3 files changed, 176 insertions(+), 46 deletions(-) diff --git a/litellm/llms/snowflake/chat/transformation.py b/litellm/llms/snowflake/chat/transformation.py index 2a23795b429..734d0e20818 100644 --- a/litellm/llms/snowflake/chat/transformation.py +++ b/litellm/llms/snowflake/chat/transformation.py @@ -236,8 +236,6 @@ class SnowflakeConfig(SnowflakeBaseConfig, OpenAIGPTConfig): stream: bool | None = None, ) -> str: api_base = self._get_api_base(api_base, optional_params) - if api_base: - api_base = api_base.rstrip("/") if _is_claude_model(model): return f"{api_base}/cortex/v1/messages" return f"{api_base}/cortex/v1/chat/completions" diff --git a/litellm/llms/snowflake/embedding/transformation.py b/litellm/llms/snowflake/embedding/transformation.py index 14b3f7c3e6d..75f35a8f379 100644 --- a/litellm/llms/snowflake/embedding/transformation.py +++ b/litellm/llms/snowflake/embedding/transformation.py @@ -26,8 +26,6 @@ class SnowflakeEmbeddingConfig(SnowflakeBaseConfig, BaseEmbeddingConfig): stream: bool | None = None, ) -> str: api_base = self._get_api_base(api_base, optional_params) - if api_base: - api_base = api_base.rstrip("/") return f"{api_base}/cortex/inference:embed" diff --git a/tests/test_litellm/llms/test_provider_url_trailing_slash.py b/tests/test_litellm/llms/test_provider_url_trailing_slash.py index 2c634ba1041..47fdb84db81 100644 --- a/tests/test_litellm/llms/test_provider_url_trailing_slash.py +++ b/tests/test_litellm/llms/test_provider_url_trailing_slash.py @@ -6,8 +6,6 @@ from litellm.llms.moonshot.chat.transformation import MoonshotChatConfig from litellm.llms.ollama.chat.transformation import OllamaChatConfig from litellm.llms.ollama.completion.transformation import OllamaConfig from litellm.llms.perplexity.embedding.transformation import PerplexityEmbeddingConfig -from litellm.llms.snowflake.chat.transformation import SnowflakeConfig -from litellm.llms.snowflake.embedding.transformation import SnowflakeEmbeddingConfig from litellm.llms.topaz.image_variations.transformation import TopazImageVariationConfig from litellm.llms.voyage.embedding.transformation import VoyageEmbeddingConfig from litellm.llms.voyage.embedding.transformation_contextual import VoyageContextualEmbeddingConfig @@ -30,8 +28,24 @@ def test_deepseek_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://custom.deepseek.com/chat/completions/", + api_key=None, + model="deepseek-chat", + optional_params={}, + litellm_params={}, + ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="deepseek-chat", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://custom.deepseek.com/chat/completions" assert url_with_slash == "https://custom.deepseek.com/chat/completions" + assert url_with_endpoint == "https://custom.deepseek.com/chat/completions" + assert url_default == "https://api.deepseek.com/beta/chat/completions" assert "//chat/completions" not in url_with_slash @@ -51,8 +65,24 @@ def test_ollama_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = chat_config.get_complete_url( + api_base="http://localhost:11434/api/chat/", + api_key=None, + model="llama3", + optional_params={}, + litellm_params={}, + ) + url_default = chat_config.get_complete_url( + api_base=None, + api_key=None, + model="llama3", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "http://localhost:11434/api/chat" assert url_with_slash == "http://localhost:11434/api/chat" + assert url_with_endpoint == "http://localhost:11434/api/chat" + assert url_default == "http://localhost:11434/api/chat" assert "//api/chat" not in url_with_slash completion_config = OllamaConfig() @@ -70,8 +100,24 @@ def test_ollama_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + comp_url_with_endpoint = completion_config.get_complete_url( + api_base="http://localhost:11434/api/generate/", + api_key=None, + model="llama3", + optional_params={}, + litellm_params={}, + ) + comp_url_default = completion_config.get_complete_url( + api_base=None, + api_key=None, + model="llama3", + optional_params={}, + litellm_params={}, + ) assert comp_url_without_slash == "http://localhost:11434/api/generate" assert comp_url_with_slash == "http://localhost:11434/api/generate" + assert comp_url_with_endpoint == "http://localhost:11434/api/generate" + assert comp_url_default == "http://localhost:11434/api/generate" assert "//api/generate" not in comp_url_with_slash @@ -91,8 +137,24 @@ def test_moonshot_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://api.moonshot.ai/v1/chat/completions/", + api_key=None, + model="moonshot-v1-8k", + optional_params={}, + litellm_params={}, + ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="moonshot-v1-8k", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://api.moonshot.ai/v1/chat/completions" assert url_with_slash == "https://api.moonshot.ai/v1/chat/completions" + assert url_with_endpoint == "https://api.moonshot.ai/v1/chat/completions" + assert url_default == "https://api.moonshot.ai/v1/chat/completions" assert "//chat/completions" not in url_with_slash @@ -112,8 +174,24 @@ def test_modelscope_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://api-inference.modelscope.cn/v1/chat/completions/", + api_key=None, + model="qwen", + optional_params={}, + litellm_params={}, + ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="qwen", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://api-inference.modelscope.cn/v1/chat/completions" assert url_with_slash == "https://api-inference.modelscope.cn/v1/chat/completions" + assert url_with_endpoint == "https://api-inference.modelscope.cn/v1/chat/completions" + assert url_default == "https://api-inference.modelscope.cn/v1/chat/completions" assert "//chat/completions" not in url_with_slash @@ -133,8 +211,24 @@ def test_jina_ai_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://api.jina.ai/v1/embeddings/", + api_key=None, + model="jina-embeddings-v2", + optional_params={}, + litellm_params={}, + ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="jina-embeddings-v2", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://api.jina.ai/v1/embeddings" assert url_with_slash == "https://api.jina.ai/v1/embeddings" + assert url_with_endpoint == "https://api.jina.ai/v1/embeddings" + assert url_default == "https://api.jina.ai/v1/embeddings" assert "//embeddings" not in url_with_slash @@ -154,8 +248,24 @@ def test_voyage_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://api.voyageai.com/v1/embeddings/", + api_key=None, + model="voyage-large-2", + optional_params={}, + litellm_params={}, + ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="voyage-large-2", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://api.voyageai.com/v1/embeddings" assert url_with_slash == "https://api.voyageai.com/v1/embeddings" + assert url_with_endpoint == "https://api.voyageai.com/v1/embeddings" + assert url_default == "https://api.voyageai.com/v1/embeddings" assert "//embeddings" not in url_with_slash contextual_config = VoyageContextualEmbeddingConfig() @@ -166,7 +276,23 @@ def test_voyage_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + c_url_endpoint = contextual_config.get_complete_url( + api_base="https://api.voyageai.com/v1/contextualizedembeddings/", + api_key=None, + model="voyage-context-2", + optional_params={}, + litellm_params={}, + ) + c_url_default = contextual_config.get_complete_url( + api_base=None, + api_key=None, + model="voyage-context-2", + optional_params={}, + litellm_params={}, + ) assert c_url == "https://api.voyageai.com/v1/contextualizedembeddings" + assert c_url_endpoint == "https://api.voyageai.com/v1/contextualizedembeddings" + assert c_url_default == "https://api.voyageai.com/v1/contextualizedembeddings" assert "//contextualizedembeddings" not in c_url multimodal_config = VoyageMultimodalEmbeddingConfig() @@ -177,7 +303,23 @@ def test_voyage_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + m_url_endpoint = multimodal_config.get_complete_url( + api_base="https://api.voyageai.com/v1/multimodalembeddings/", + api_key=None, + model="voyage-multimodal-3", + optional_params={}, + litellm_params={}, + ) + m_url_default = multimodal_config.get_complete_url( + api_base=None, + api_key=None, + model="voyage-multimodal-3", + optional_params={}, + litellm_params={}, + ) assert m_url == "https://api.voyageai.com/v1/multimodalembeddings" + assert m_url_endpoint == "https://api.voyageai.com/v1/multimodalembeddings" + assert m_url_default == "https://api.voyageai.com/v1/multimodalembeddings" assert "//multimodalembeddings" not in m_url @@ -197,8 +339,24 @@ def test_perplexity_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://api.perplexity.ai/v1/embeddings/", + api_key=None, + model="sonar-medium", + optional_params={}, + litellm_params={}, + ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="sonar-medium", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://api.perplexity.ai/v1/embeddings" assert url_with_slash == "https://api.perplexity.ai/v1/embeddings" + assert url_with_endpoint == "https://api.perplexity.ai/v1/embeddings" + assert url_default == "https://api.perplexity.ai/v1/embeddings" assert "//v1/embeddings" not in url_with_slash @@ -218,8 +376,16 @@ def test_heroku_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_with_endpoint = config.get_complete_url( + api_base="https://my-app.herokuapp.com/v1/chat/completions/", + api_key=None, + model="claude-3-5-sonnet", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://my-app.herokuapp.com/v1/chat/completions" assert url_with_slash == "https://my-app.herokuapp.com/v1/chat/completions" + assert url_with_endpoint == "https://my-app.herokuapp.com/v1/chat/completions" assert "//v1/chat/completions" not in url_with_slash @@ -239,46 +405,14 @@ def test_topaz_get_complete_url_trailing_slash(): optional_params={}, litellm_params={}, ) + url_default = config.get_complete_url( + api_base=None, + api_key=None, + model="topaz-v1", + optional_params={}, + litellm_params={}, + ) assert url_without_slash == "https://api.topazlabs.com/image/v1/enhance" assert url_with_slash == "https://api.topazlabs.com/image/v1/enhance" + assert url_default == "https://api.topazlabs.com/image/v1/enhance" assert "//image/v1/enhance" not in url_with_slash - - -def test_snowflake_get_complete_url_trailing_slash(): - chat_config = SnowflakeConfig() - url_without_slash = chat_config.get_complete_url( - api_base="https://myaccount.snowflakecomputing.com", - api_key=None, - model="snowflake-arctic", - optional_params={}, - litellm_params={}, - ) - url_with_slash = chat_config.get_complete_url( - api_base="https://myaccount.snowflakecomputing.com/", - api_key=None, - model="snowflake-arctic", - optional_params={}, - litellm_params={}, - ) - assert url_without_slash == "https://myaccount.snowflakecomputing.com/api/v2/cortex/v1/chat/completions" - assert url_with_slash == "https://myaccount.snowflakecomputing.com/api/v2/cortex/v1/chat/completions" - assert "//api/v2" not in url_with_slash - - embed_config = SnowflakeEmbeddingConfig() - embed_url_without_slash = embed_config.get_complete_url( - api_base="https://myaccount.snowflakecomputing.com", - api_key=None, - model="snowflake-arctic-embed", - optional_params={}, - litellm_params={}, - ) - embed_url_with_slash = embed_config.get_complete_url( - api_base="https://myaccount.snowflakecomputing.com/", - api_key=None, - model="snowflake-arctic-embed", - optional_params={}, - litellm_params={}, - ) - assert embed_url_without_slash == "https://myaccount.snowflakecomputing.com/api/v2/cortex/inference:embed" - assert embed_url_with_slash == "https://myaccount.snowflakecomputing.com/api/v2/cortex/inference:embed" - assert "//api/v2" not in embed_url_with_slash