diff --git a/README.md b/README.md index c4aeee80fb4..3074e47bd1f 100644 --- a/README.md +++ b/README.md @@ -464,6 +464,7 @@ Set `LITELLM_PROXY_API_BASE` and `LITELLM_PROXY_API_KEY` and every model call th | [Together AI (`together_ai`)](https://docs.litellm.ai/docs/providers/togetherai) | ✅ | ✅ | ✅ | | | | | | | | | [Topaz (`topaz`)](https://docs.litellm.ai/docs/providers/topaz) | ✅ | ✅ | ✅ | | | | | | | | | [Triton (`triton`)](https://docs.litellm.ai/docs/providers/triton-inference-server) | ✅ | ✅ | ✅ | | | | | | | | +| [Turion (`turion`)](https://turion.ai/docs/guides/garden/) | | | | | | | | | | | | [Typesafe Decisions API (`typesafe`)](https://docs.litellm.ai/docs/providers) | | | | | | | | | | | | [V0 (`v0`)](https://docs.litellm.ai/docs/providers/v0) | ✅ | ✅ | ✅ | | | | | | | | | [Vercel AI Gateway (`vercel_ai_gateway`)](https://docs.litellm.ai/docs/providers/vercel_ai_gateway) | ✅ | ✅ | ✅ | | | | | | | | diff --git a/litellm/__init__.py b/litellm/__init__.py index 102c4d1440f..8567dae5f04 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -1753,6 +1753,9 @@ if TYPE_CHECKING: from .llms.nace.decisions.transformation import ( NaceDecisionsConfig as NaceDecisionsConfig, ) + from .llms.turion.decisions.transformation import ( + TurionDecisionsConfig as TurionDecisionsConfig, + ) from .llms.typesafe.decisions.transformation import ( TypeSafeDecisionsConfig as TypeSafeDecisionsConfig, ) @@ -1771,6 +1774,9 @@ if TYPE_CHECKING: from .llms.cloudflare.extraction.transformation import ( CloudflareExtractionConfig as CloudflareExtractionConfig, ) + from .llms.turion.extraction.transformation import ( + TurionExtractionConfig as TurionExtractionConfig, + ) from .llms.strands_decider.decisions.transformation import ( StrandsDeciderDecisionsConfig as StrandsDeciderDecisionsConfig, ) diff --git a/litellm/_lazy_imports_registry.py b/litellm/_lazy_imports_registry.py index 65074093dbb..99041ad46d4 100644 --- a/litellm/_lazy_imports_registry.py +++ b/litellm/_lazy_imports_registry.py @@ -165,10 +165,12 @@ LLM_CONFIG_NAMES: Final = ( "TypeSafeDecisionsConfig", "ParallelAIDecisionsConfig", "NaceDecisionsConfig", + "TurionDecisionsConfig", "OpenRouterDecisionsConfig", "FireworksAIDecisionsConfig", "CloudflareDecisionsConfig", "CloudflareExtractionConfig", + "TurionExtractionConfig", "StrandsDeciderDecisionsConfig", "DatabricksDecisionsConfig", "HostedVLLMDecisionsConfig", @@ -740,12 +742,14 @@ _LLM_CONFIGS_IMPORT_MAP: Final = { ), "PerplexityDecisionsConfig": (".llms.perplexity.decisions.transformation", "PerplexityDecisionsConfig"), "NaceDecisionsConfig": (".llms.nace.decisions.transformation", "NaceDecisionsConfig"), + "TurionDecisionsConfig": (".llms.turion.decisions.transformation", "TurionDecisionsConfig"), "TypeSafeDecisionsConfig": (".llms.typesafe.decisions.transformation", "TypeSafeDecisionsConfig"), "ParallelAIDecisionsConfig": (".llms.parallel_ai.decisions.transformation", "ParallelAIDecisionsConfig"), "OpenRouterDecisionsConfig": (".llms.openrouter.decisions.transformation", "OpenRouterDecisionsConfig"), "FireworksAIDecisionsConfig": (".llms.fireworks_ai.decisions.transformation", "FireworksAIDecisionsConfig"), "CloudflareDecisionsConfig": (".llms.cloudflare.decisions.transformation", "CloudflareDecisionsConfig"), "CloudflareExtractionConfig": (".llms.cloudflare.extraction.transformation", "CloudflareExtractionConfig"), + "TurionExtractionConfig": (".llms.turion.extraction.transformation", "TurionExtractionConfig"), "StrandsDeciderDecisionsConfig": ( ".llms.strands_decider.decisions.transformation", "StrandsDeciderDecisionsConfig", diff --git a/litellm/llms/turion/decisions/transformation.py b/litellm/llms/turion/decisions/transformation.py new file mode 100644 index 00000000000..91a0d7e55d8 --- /dev/null +++ b/litellm/llms/turion/decisions/transformation.py @@ -0,0 +1,9 @@ +from litellm.llms.base_llm.decisions.transformation import BaseDecisionsConfig + + +class TurionDecisionsConfig(BaseDecisionsConfig): + api_key_env = ("TURION_API_KEY", "TURION_API_TOKEN") + api_base_env = ("TURION_API_BASE",) + + def get_default_api_base(self) -> str | None: + return "https://api.turion.ai" diff --git a/litellm/llms/turion/extraction/transformation.py b/litellm/llms/turion/extraction/transformation.py new file mode 100644 index 00000000000..944ab209d46 --- /dev/null +++ b/litellm/llms/turion/extraction/transformation.py @@ -0,0 +1,13 @@ +from litellm.litellm_core_utils.url_utils import join_api_base +from litellm.llms.base_llm.extraction.transformation import BaseExtractionConfig + + +class TurionExtractionConfig(BaseExtractionConfig): + api_key_env = ("TURION_API_KEY", "TURION_API_TOKEN") + api_base_env = ("TURION_API_BASE",) + + def get_default_api_base(self) -> str | None: + return "https://api.turion.ai" + + def get_complete_url(self, api_base: str, model: str) -> str: + return join_api_base(api_base.rstrip("/").removesuffix("/v1"), "/v1/extract") diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 5a46a0891fc..08a521d8403 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -73187,6 +73187,26 @@ "output_cost_per_token": 0.0, "source": "https://console.nace.ai/docs/drex/reference/models" }, + "turion/turion-extract-alpha": { + "input_cost_per_token": 5e-08, + "litellm_provider": "turion", + "max_input_tokens": 16384, + "mode": "extraction", + "output_cost_per_token": 0.0, + "source": "https://turion.ai/docs/guides/usage/#pricing" + }, + "turion/turion-jev-31b": { + "input_cost_per_token": 2.1e-08, + "litellm_provider": "turion", + "max_input_tokens": 16384, + "mode": "evaluation", + "output_cost_per_token": 0.0, + "source": "https://turion.ai/docs/guides/usage/#pricing", + "supported_endpoints": [ + "/v1/decisions", + "/v1/systemone" + ] + }, "typesafe/jev-1.13.0": { "input_cost_per_token": 4.2e-08, "litellm_provider": "typesafe", diff --git a/litellm/provider_endpoints_support_backup.json b/litellm/provider_endpoints_support_backup.json index 40ea9d15ff4..034f8324e54 100644 --- a/litellm/provider_endpoints_support_backup.json +++ b/litellm/provider_endpoints_support_backup.json @@ -4046,6 +4046,32 @@ "generateContent": false } }, + "turion": { + "display_name": "Turion (`turion`)", + "url": "https://turion.ai/docs/guides/garden/", + "endpoints": { + "chat_completions": false, + "responses": false, + "text_completion": false, + "embeddings": false, + "image_generations": false, + "image_edits": false, + "audio_transcriptions": false, + "audio_speech": false, + "rerank": false, + "ocr": false, + "search": false, + "moderations": false, + "realtime": false, + "video_generations": false, + "batches": false, + "messages": false, + "interactions": false, + "systemone": true, + "a2a": false, + "generateContent": false + } + }, "typesafe": { "display_name": "TypeSafe (`typesafe`)", "url": "https://docs.typesafe.ai/models", diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index aa7554c4a5a..1362525a71a 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -2669,6 +2669,34 @@ ], "default_model_placeholder": "parallel_ai/decision" }, + { + "provider": "Turion", + "provider_display_name": "Turion", + "litellm_provider": "turion", + "credential_fields": [ + { + "key": "api_base", + "label": "API Base", + "placeholder": "https://api.turion.ai", + "tooltip": null, + "required": false, + "field_type": "text", + "options": null, + "default_value": null + }, + { + "key": "api_key", + "label": "API Key", + "placeholder": null, + "tooltip": null, + "required": true, + "field_type": "password", + "options": null, + "default_value": null + } + ], + "default_model_placeholder": "turion/turion-jev-31b" + }, { "provider": "NEBIUS", "provider_display_name": "Nebius", diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 57f4d971eb3..cb3490df07e 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -4625,6 +4625,7 @@ class LlmProviders(str, Enum): TYPESAFE = "typesafe" PARALLEL_AI = "parallel_ai" NACE = "nace" + TURION = "turion" STRANDS_DECIDER = "strands_decider" LAYA = "laya" BESPOKE = "bespoke" diff --git a/litellm/utils.py b/litellm/utils.py index e003f0a3987..4b6a3b5e9b9 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -10281,6 +10281,7 @@ class ProviderConfigManager: LlmProviders.AZURE_AI, LlmProviders.EU_JEV, LlmProviders.PARALLEL_AI, + LlmProviders.TURION, ): configs: Final = { LlmProviders.OPENAI: litellm.OpenAIDecisionsConfig, @@ -10288,6 +10289,7 @@ class ProviderConfigManager: LlmProviders.AZURE_AI: litellm.AzureAIDecisionsConfig, LlmProviders.EU_JEV: litellm.EuJevDecisionsConfig, LlmProviders.PARALLEL_AI: litellm.ParallelAIDecisionsConfig, + LlmProviders.TURION: litellm.TurionDecisionsConfig, } return configs[provider]() return None @@ -10296,6 +10298,8 @@ class ProviderConfigManager: def get_provider_extraction_config(model: str, provider: LlmProviders) -> BaseExtractionConfig | None: if provider == LlmProviders.CLOUDFLARE: return litellm.CloudflareExtractionConfig() + if provider == LlmProviders.TURION: + return litellm.TurionExtractionConfig() return None @staticmethod diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 5a46a0891fc..08a521d8403 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -73187,6 +73187,26 @@ "output_cost_per_token": 0.0, "source": "https://console.nace.ai/docs/drex/reference/models" }, + "turion/turion-extract-alpha": { + "input_cost_per_token": 5e-08, + "litellm_provider": "turion", + "max_input_tokens": 16384, + "mode": "extraction", + "output_cost_per_token": 0.0, + "source": "https://turion.ai/docs/guides/usage/#pricing" + }, + "turion/turion-jev-31b": { + "input_cost_per_token": 2.1e-08, + "litellm_provider": "turion", + "max_input_tokens": 16384, + "mode": "evaluation", + "output_cost_per_token": 0.0, + "source": "https://turion.ai/docs/guides/usage/#pricing", + "supported_endpoints": [ + "/v1/decisions", + "/v1/systemone" + ] + }, "typesafe/jev-1.13.0": { "input_cost_per_token": 4.2e-08, "litellm_provider": "typesafe", diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 40ea9d15ff4..034f8324e54 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -4046,6 +4046,32 @@ "generateContent": false } }, + "turion": { + "display_name": "Turion (`turion`)", + "url": "https://turion.ai/docs/guides/garden/", + "endpoints": { + "chat_completions": false, + "responses": false, + "text_completion": false, + "embeddings": false, + "image_generations": false, + "image_edits": false, + "audio_transcriptions": false, + "audio_speech": false, + "rerank": false, + "ocr": false, + "search": false, + "moderations": false, + "realtime": false, + "video_generations": false, + "batches": false, + "messages": false, + "interactions": false, + "systemone": true, + "a2a": false, + "generateContent": false + } + }, "typesafe": { "display_name": "TypeSafe (`typesafe`)", "url": "https://docs.typesafe.ai/models", diff --git a/tests/integration/providers/test_decisions_wire.py b/tests/integration/providers/test_decisions_wire.py index 4e091460667..4e1e45a1ff1 100644 --- a/tests/integration/providers/test_decisions_wire.py +++ b/tests/integration/providers/test_decisions_wire.py @@ -91,6 +91,9 @@ _PROVIDERS: Final = ( ), _Provider("typesafe", "typesafe/jev-1.13.0", "/v1/systemone", "jev-1.13.0", _API_KEY, False, "typesafe/jev-1.13.0"), _Provider("nace", "nace/drex-v2.0", "/v1/systemone", "drex-v2.0", _API_KEY, False, "nace/drex-v2.0"), + _Provider( + "turion", "turion/turion-jev-31b", "/v1/systemone", "turion-jev-31b", _API_KEY, False, "turion/turion-jev-31b" + ), _Provider( "openrouter", "openrouter/typesafe/jev-1.13", diff --git a/tests/unit/llms/base_llm/decisions/test_base_decisions_transformation.py b/tests/unit/llms/base_llm/decisions/test_base_decisions_transformation.py index 2ef202762ff..919f45ecb76 100644 --- a/tests/unit/llms/base_llm/decisions/test_base_decisions_transformation.py +++ b/tests/unit/llms/base_llm/decisions/test_base_decisions_transformation.py @@ -392,7 +392,7 @@ def test_only_a_provider_without_confidence_may_omit_it( assert raised.value.status_code == 500 -@pytest.mark.parametrize("provider", ("nace", "openrouter", "fireworks_ai", "typesafe")) +@pytest.mark.parametrize("provider", ("nace", "openrouter", "fireworks_ai", "typesafe", "turion")) @pytest.mark.parametrize("legend", (["low", "high"], {"0": "low", "1": "high"})) def test_score_legends_preserve_labels_probabilities_and_metadata(provider: str, legend: object) -> None: config: Final = ProviderConfigManager.get_provider_decisions_config("drex-v2.0", LlmProviders(provider)) @@ -438,7 +438,7 @@ def test_score_legends_preserve_labels_probabilities_and_metadata(provider: str, @pytest.mark.parametrize( "payload", ([], {"answers": []}, {"answers": {"a": None}}, {"answers": {"a": {"type": "score", "legend": [1]}}}) ) -@pytest.mark.parametrize("provider", ("nace", "openrouter", "fireworks_ai", "typesafe")) +@pytest.mark.parametrize("provider", ("nace", "openrouter", "fireworks_ai", "typesafe", "turion")) def test_invalid_provider_response_is_an_api_error(payload: object, provider: str) -> None: config: Final = ProviderConfigManager.get_provider_decisions_config("drex-v2.0", LlmProviders(provider)) assert config is not None @@ -502,7 +502,7 @@ def test_score_probabilities_preserve_missing_entries_and_explicit_zeros( @pytest.mark.parametrize("raw_content", (b"", b"not-json", b'{"answers":')) -@pytest.mark.parametrize("provider", ("nace", "openrouter", "fireworks_ai", "typesafe", "openai")) +@pytest.mark.parametrize("provider", ("nace", "openrouter", "fireworks_ai", "typesafe", "turion", "openai")) def test_non_json_provider_response_is_an_api_error(raw_content: bytes, provider: str) -> None: config: Final = ProviderConfigManager.get_provider_decisions_config("drex-v2.0", LlmProviders(provider)) assert config is not None diff --git a/tests/unit/llms/turion/__init__.py b/tests/unit/llms/turion/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/llms/turion/test_turion_transformation.py b/tests/unit/llms/turion/test_turion_transformation.py new file mode 100644 index 00000000000..79a294b25b6 --- /dev/null +++ b/tests/unit/llms/turion/test_turion_transformation.py @@ -0,0 +1,149 @@ +import json +from collections.abc import Mapping +from typing import Final + +import httpx +import pytest + +import litellm +from litellm.llms.base_llm.decisions.transformation import systemone_request_to_ir +from litellm.llms.base_llm.extraction.transformation import BaseExtractionConfig +from litellm.types.decisions import DecisionsIRChoiceAnswer, DecisionsRequestBody +from litellm.types.extraction import ExtractionRequestBody +from litellm.types.utils import LlmProviders +from litellm.utils import ProviderConfigManager + +# Bodies as https://api.turion.ai answered them (POST /v1/systemone and POST /v1/extract). +TURION_SYSTEMONE_RESPONSE: Final = { + "model": "turion-jev-31b", + "answers": { + "refund": {"type": "noul", "noul": 0.892483}, + "team": { + "type": "choice", + "choice": "billing", + "probabilities": {"billing": 0.991577, "technical": 0.008423}, + "confidence": 0.991577, + }, + "urgency": { + "type": "score", + "score": 1.128746, + "legend": {"0": "Can wait", "1": "This week", "2": "Right now"}, + "probabilities": {"0": 0.17257, "1": 0.526114, "2": 0.301316}, + "confidence": 0.526114, + }, + }, + "usage": {"input_tokens": 409, "output_tokens": 0}, +} +TURION_EXTRACT_RESPONSE: Final = { + "id": "01a193fd-bf10-742e-a4a4-8f1865b3b83d", + "model": "turion-extract-alpha", + "answers": { + "invoice_number": { + "type": "text", + "value": "INV-2291", + "p_null": 0.00012, + "confidence": 0.99988, + "span": [8, 16], + }, + "total": {"type": "number", "value": 1080, "p_null": 0.000008, "confidence": 0.999992}, + }, + "truncated": False, + "usage": {"input_tokens": 106, "output_tokens": 0, "passes": 1}, +} + + +def _extraction_config() -> BaseExtractionConfig: + config: Final = ProviderConfigManager.get_provider_extraction_config("turion-extract-alpha", LlmProviders.TURION) + assert config is not None + return config + + +def test_turion_serves_decisions_and_extraction() -> None: + assert isinstance( + ProviderConfigManager.get_provider_decisions_config("turion-jev-31b", LlmProviders.TURION), + litellm.TurionDecisionsConfig, + ) + assert isinstance(_extraction_config(), litellm.TurionExtractionConfig) + + +@pytest.mark.parametrize("api_base", ("https://api.turion.ai", "https://api.turion.ai/", "https://api.turion.ai/v1")) +def test_routes_to_the_turion_api(monkeypatch: pytest.MonkeyPatch, api_base: str) -> None: + monkeypatch.delenv("TURION_API_BASE", raising=False) + decisions: Final = ProviderConfigManager.get_provider_decisions_config("turion-jev-31b", LlmProviders.TURION) + assert decisions is not None + assert decisions.resolve_api_base(None) == "https://api.turion.ai" + assert _extraction_config().resolve_api_base(None) == "https://api.turion.ai" + assert decisions.get_complete_url(api_base, "turion-jev-31b") == "https://api.turion.ai/v1/systemone" + assert _extraction_config().get_complete_url(api_base, "turion-extract-alpha") == "https://api.turion.ai/v1/extract" + + +def test_reads_turion_api_key_then_the_turion_cli_token(monkeypatch: pytest.MonkeyPatch) -> None: + config: Final = _extraction_config() + monkeypatch.delenv("TURION_API_KEY", raising=False) + monkeypatch.setenv("TURION_API_TOKEN", "tk_from_the_cli") + assert config.resolve_api_key(None) == "tk_from_the_cli" + monkeypatch.setenv("TURION_API_KEY", "tk_litellm") + assert config.resolve_api_key(None) == "tk_litellm" + assert config.resolve_api_key("tk_explicit") == "tk_explicit" + + +def test_extraction_request_keeps_the_clairic_body() -> None: + body: Final = _extraction_config().transform_extraction_request( + "turion-extract-alpha", + ExtractionRequestBody.model_validate( + { + "state": "Invoice INV-2291 issued 2026-09-02. Total $1080.", + "fields": {"invoice_number": {"type": "text"}, "total": {"type": "number"}}, + "reference_date": "2026-10-20", + } + ), + ) + fields: Final = body["fields"] + assert body["model"] == "turion-extract-alpha" + assert body["reference_date"] == "2026-10-20" + assert isinstance(fields, Mapping) + assert list(fields) == ["invoice_number", "total"] + + +def test_extraction_response_parses_turion_answers() -> None: + response: Final = _extraction_config().transform_extraction_response( + "turion-extract-alpha", + "turion", + httpx.Response(status_code=200, content=json.dumps(TURION_EXTRACT_RESPONSE).encode()), + ) + assert response.truncated is False + assert response.answers["invoice_number"].value == "INV-2291" + assert response.answers["invoice_number"].span == (8, 16) + assert response.answers["total"].value == 1080 + assert response.usage.input_tokens == 106 + + +def test_systemone_response_parses_turion_answers() -> None: + config: Final = ProviderConfigManager.get_provider_decisions_config("turion-jev-31b", LlmProviders.TURION) + assert config is not None + request: Final = systemone_request_to_ir( + DecisionsRequestBody.model_validate( + { + "state": "I was charged twice for my subscription.", + "questions": { + "refund": {"type": "noul", "instructions": "Is the customer asking for money back?"}, + "team": { + "type": "choice", + "instructions": "Which team should handle this?", + "criteria": {"billing": "Charges and refunds", "technical": "Bugs and outages"}, + }, + "urgency": { + "type": "score", + "instructions": "How urgent is this?", + "criteria": ["Can wait", "This week", "Right now"], + }, + }, + } + ) + ) + response: Final = config.parse_response(TURION_SYSTEMONE_RESPONSE, request) + assert len(response.answers) == 3 + team: Final = next(answer for answer in response.answers if isinstance(answer, DecisionsIRChoiceAnswer)) + assert team.choice == "billing" + assert response.usage is not None + assert response.usage.input_tokens == 409 diff --git a/tests/unit/proxy/public_endpoints/test_public_endpoints.py b/tests/unit/proxy/public_endpoints/test_public_endpoints.py index 29413d2b189..461dac66f29 100644 --- a/tests/unit/proxy/public_endpoints/test_public_endpoints.py +++ b/tests/unit/proxy/public_endpoints/test_public_endpoints.py @@ -528,6 +528,7 @@ def _decisions_provider_entry(provider: str) -> ProviderCreateInfo: ("TypeSafe", "TypeSafe", LlmProviders.TYPESAFE), ("Nace", "Nace", LlmProviders.NACE), ("PARALLEL_AI", "Parallel AI", LlmProviders.PARALLEL_AI), + ("Turion", "Turion", LlmProviders.TURION), ("EU_JEV", "eu/jev", LlmProviders.EU_JEV), ), ) diff --git a/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx b/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx index c88e44f21d4..8e34ffb9685 100644 --- a/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx +++ b/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx @@ -269,6 +269,7 @@ describe("provider_info_helpers", () => { Providers.PREDIBASE, Providers.Sail, Providers.StreamLake, + Providers.Turion, Providers.WANDB, Providers.ZAI, Providers.ZeroGPU, @@ -603,6 +604,20 @@ describe("provider_info_helpers", () => { expect(getPlaceholder("Nace")).toBe("nace/drex-latest"); }); + it("lists Turion's decision and extraction models and resolves the provider name and model placeholder", () => { + const modelMap = { + "turion/turion-jev-31b": { litellm_provider: "turion", mode: "evaluation" }, + "turion/turion-extract-alpha": { litellm_provider: "turion", mode: "extraction" }, + "typesafe/jev-latest": { litellm_provider: "typesafe", mode: "evaluation" }, + }; + expect(getProviderModels(Providers.Turion, modelMap)).toEqual([ + "turion/turion-jev-31b", + "turion/turion-extract-alpha", + ]); + expect(getProviderLogoAndName("turion").displayName).toBe("Turion"); + expect(getPlaceholder("Turion")).toBe("turion/turion-jev-31b"); + }); + it("should list only typesafe decision models for the 'TypeSafe' provider key, not the OpenRouter-hosted one", () => { const modelMap = { "typesafe/jev-latest": { litellm_provider: "typesafe", mode: "evaluation" }, diff --git a/ui/litellm-dashboard/src/components/provider_info_helpers.tsx b/ui/litellm-dashboard/src/components/provider_info_helpers.tsx index 1680258e10b..79dcc1e695c 100644 --- a/ui/litellm-dashboard/src/components/provider_info_helpers.tsx +++ b/ui/litellm-dashboard/src/components/provider_info_helpers.tsx @@ -193,6 +193,7 @@ export enum Providers { TypeSafe = "TypeSafe", Nace = "Nace", PARALLEL_AI = "Parallel AI", + Turion = "Turion", V0 = "V0", VERCEL_AI_GATEWAY = "Vercel Ai Gateway", Vertex_AI = "Vertex AI (Anthropic, Gemini, etc.)", @@ -328,6 +329,7 @@ export const provider_map: Record = { TypeSafe: "typesafe", Nace: "nace", PARALLEL_AI: "parallel_ai", + Turion: "turion", V0: "v0", VERCEL_AI_GATEWAY: "vercel_ai_gateway", Vertex_AI: "vertex_ai", @@ -519,6 +521,7 @@ const providerPlaceholderMap: Partial> = { [Providers.TypeSafe]: "typesafe/jev-latest", [Providers.Nace]: "nace/drex-latest", [Providers.PARALLEL_AI]: "parallel_ai/decision", + [Providers.Turion]: "turion/turion-jev-31b", [Providers.StreamLake]: "streamlake/", [Providers.Vertex_AI]: "gemini-pro", [Providers.VolcEngine]: "volcengine/",