diff --git a/litellm/constants.py b/litellm/constants.py index ae98b37d6e6..3e354d59a7e 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -771,6 +771,7 @@ openai_compatible_endpoints: List = [ "https://api.moonshot.ai/v1", "https://api.publicai.co/v1", "https://api.synthetic.new/openai/v1", + "https://serverless.tensormesh.ai/v1", "https://api.stima.tech/v1", "https://nano-gpt.com/api/v1", "https://api.poe.com/v1", @@ -820,6 +821,7 @@ openai_compatible_providers: List = [ "meta_llama", "publicai", # PublicAI - JSON-configured provider "synthetic", # Synthetic - JSON-configured provider + "tensormesh", # Tensormesh - JSON-configured provider "apertis", # Apertis - JSON-configured provider "nano-gpt", # Nano-GPT - JSON-configured provider "poe", # Poe - JSON-configured provider @@ -855,6 +857,7 @@ openai_text_completion_compatible_providers: List = ( "moonshot", "publicai", "synthetic", + "tensormesh", "apertis", "nano-gpt", "poe", diff --git a/litellm/llms/openai_like/providers.json b/litellm/llms/openai_like/providers.json index b5e5aa4ea28..c9257677fd1 100644 --- a/litellm/llms/openai_like/providers.json +++ b/litellm/llms/openai_like/providers.json @@ -114,5 +114,14 @@ "param_mappings": { "max_completion_tokens": "max_tokens" } + }, + "tensormesh": { + "base_url": "https://serverless.tensormesh.ai/v1", + "api_key_env": "TENSORMESH_INFERENCE_API_KEY", + "api_base_env": "TENSORMESH_SERVERLESS_BASE_URL", + "base_class": "openai_gpt", + "param_mappings": { + "max_completion_tokens": "max_tokens" + } } } diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 5574d616fac..8f23f89ead9 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -3364,6 +3364,7 @@ class LlmProviders(str, Enum): POE = "poe" CHUTES = "chutes" XIAOMI_MIMO = "xiaomi_mimo" + TENSORMESH = "tensormesh" LITELLM_AGENT = "litellm_agent" CURSOR = "cursor" BEDROCK_MANTLE = "bedrock_mantle" diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 388752b032e..abd03e1c957 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -2079,6 +2079,24 @@ "a2a": false } }, + "tensormesh": { + "display_name": "Tensormesh (`tensormesh`)", + "url": "https://docs.litellm.ai/docs/providers/tensormesh", + "endpoints": { + "chat_completions": true, + "messages": true, + "responses": false, + "embeddings": false, + "image_generations": false, + "audio_transcriptions": false, + "audio_speech": false, + "moderations": false, + "batches": false, + "rerank": false, + "a2a": false, + "text_completion": true + } + }, "text-completion-codestral": { "display_name": "Text Completion Codestral (`text-completion-codestral`)", "url": "https://docs.litellm.ai/docs/providers/codestral", diff --git a/tests/test_litellm/llms/openai_like/test_tensormesh_provider.py b/tests/test_litellm/llms/openai_like/test_tensormesh_provider.py new file mode 100644 index 00000000000..f81f1c00a7b --- /dev/null +++ b/tests/test_litellm/llms/openai_like/test_tensormesh_provider.py @@ -0,0 +1,84 @@ +""" +Tests for Tensormesh provider configuration and integration. +""" + +import litellm + + +class TestTensormeshProviderConfig: + """Test Tensormesh provider configuration""" + + def test_tensormesh_in_provider_list(self): + """Test that tensormesh is in the provider list""" + from litellm import LlmProviders + + assert hasattr(LlmProviders, "TENSORMESH") + assert LlmProviders.TENSORMESH.value == "tensormesh" + assert "tensormesh" in litellm.provider_list + + def test_tensormesh_json_config_exists(self): + """Test that tensormesh is configured in providers.json""" + from litellm.llms.openai_like.json_loader import JSONProviderRegistry + + assert JSONProviderRegistry.exists("tensormesh") + + tensormesh = JSONProviderRegistry.get("tensormesh") + assert tensormesh is not None + assert tensormesh.base_url == "https://serverless.tensormesh.ai/v1" + assert tensormesh.api_key_env == "TENSORMESH_INFERENCE_API_KEY" + assert tensormesh.api_base_env == "TENSORMESH_SERVERLESS_BASE_URL" + assert tensormesh.param_mappings.get("max_completion_tokens") == "max_tokens" + + def test_tensormesh_provider_resolution(self): + """Test that provider resolution finds tensormesh and the default base URL""" + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + model, provider, api_key, api_base = get_llm_provider( + model="tensormesh/openai/gpt-oss-120b", + custom_llm_provider=None, + api_base=None, + api_key=None, + ) + + assert model == "openai/gpt-oss-120b" + assert provider == "tensormesh" + assert api_base == "https://serverless.tensormesh.ai/v1" + + def test_tensormesh_api_base_override(self): + """Test that an explicit api_base / api_key overrides the serverless default""" + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + model, provider, api_key, api_base = get_llm_provider( + model="tensormesh/openai/gpt-oss-120b", + custom_llm_provider=None, + api_base="https://custom.example.com/v1", + api_key="sk-test", + ) + + assert provider == "tensormesh" + assert api_base == "https://custom.example.com/v1" + assert api_key == "sk-test" + + def test_tensormesh_text_completion_enabled(self): + """Tensormesh is wired for the /completions (text completion) route, + matching the text_completion flag in provider_endpoints_support.json.""" + assert "tensormesh" in litellm.openai_text_completion_compatible_providers + + def test_tensormesh_router_config(self): + """Test that tensormesh can be used in Router configuration""" + from litellm import Router + + router = Router( + model_list=[ + { + "model_name": "tensormesh-chat", + "litellm_params": { + "model": "tensormesh/openai/gpt-oss-120b", + "api_key": "test-key", + }, + } + ] + ) + + assert len(router.model_list) == 1 + assert router.model_list[0]["model_name"] == "tensormesh-chat"