diff --git a/litellm/__init__.py b/litellm/__init__.py
index 5f14c605cd0..f64531f86fb 100644
--- a/litellm/__init__.py
+++ b/litellm/__init__.py
@@ -7,7 +7,6 @@ _apply_process_defaults()
### INIT VARIABLES #########################
import threading
import os
-import datetime
from collections.abc import Mapping, Sequence
from typing import (
@@ -550,6 +549,7 @@ _key_management_system: Optional["KeyManagementSystem"] = None
output_parse_pii: bool = False
#############################################
from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map, mark_litellm_import_complete
+from litellm.litellm_core_utils.model_retirement import is_hidden_as_retired
model_cost = get_model_cost_map(url=model_cost_map_url)
cost_discount_config: Dict[str, float] = {} # Provider-specific cost discounts {"vertex_ai": 0.05} = 5% discount
@@ -756,16 +756,6 @@ def is_openai_finetune_model(key: str) -> bool:
return key.startswith("ft:") and not key.count(":") > 1
-def _is_past_deprecation_date(value: Mapping[str, object]) -> bool:
- deprecation_date: Final = value.get("deprecation_date")
- if not isinstance(deprecation_date, str):
- return False
- try:
- return datetime.date.fromisoformat(deprecation_date) <= datetime.date.today()
- except ValueError:
- return False
-
-
def _populate_provider_model_sets(model_cost_map: Mapping[str, Mapping[str, object]]) -> None:
for key, value in tuple(model_cost_map.items()):
if value.get("litellm_provider") == "openai" and not is_openai_finetune_model(key):
@@ -873,12 +863,12 @@ def _populate_provider_model_sets(model_cost_map: Mapping[str, Mapping[str, obje
if "-to-" not in key and "fireworks-ai-default" not in key:
fireworks_ai_models.add(key)
elif value.get("litellm_provider") == "together_ai":
- if _is_past_deprecation_date(value):
+ if is_hidden_as_retired(value):
together_ai_models.discard(key)
elif not key.startswith("together-ai-"):
together_ai_models.add(key)
elif value.get("litellm_provider") == "baseten":
- if _is_past_deprecation_date(value):
+ if is_hidden_as_retired(value):
baseten_models.discard(key)
else:
baseten_models.add(key)
@@ -1051,7 +1041,10 @@ def _populate_provider_model_sets(model_cost_map: Mapping[str, Mapping[str, obje
elif value.get("litellm_provider") == "coralbricks":
coralbricks_models.add(key)
elif value.get("litellm_provider") == "aiand":
- aiand_models.add(key)
+ if is_hidden_as_retired(value):
+ aiand_models.discard(key)
+ else:
+ aiand_models.add(key)
elif value.get("litellm_provider") == "reducto":
reducto_models.add(key)
elif value.get("litellm_provider") == "bedrock_mantle":
diff --git a/litellm/litellm_core_utils/llm_request_utils.py b/litellm/litellm_core_utils/llm_request_utils.py
index 9c2ec0b8984..84f161e0c62 100644
--- a/litellm/litellm_core_utils/llm_request_utils.py
+++ b/litellm/litellm_core_utils/llm_request_utils.py
@@ -1,4 +1,3 @@
-import datetime
from collections.abc import Iterable, Iterator, Mapping
from dataclasses import dataclass
from typing import Final, cast
@@ -9,6 +8,7 @@ from typing_extensions import NotRequired, ReadOnly, TypedDict
import litellm
from litellm.constants import DEFAULT_MAX_RECURSE_DEPTH
from litellm.litellm_core_utils.get_llm_provider_logic import inferred_provider
+from litellm.litellm_core_utils.model_retirement import is_past_deprecation_date
def _form_field_value(value: object) -> str:
@@ -168,7 +168,9 @@ class RankedChatModel:
def rank_chat_models_from_llm_provider(custom_llm_provider: str) -> tuple[RankedChatModel, ...]:
- known_models: Final[Iterable[str]] = litellm.models_by_provider.get(custom_llm_provider, ())
+ from litellm.utils import bundled_provider_models
+
+ known_models: Final = bundled_provider_models(custom_llm_provider)
ranked_models: Final = (
RankedChatModel(
model=model, route_rank=route_rank, cost=cost, is_past_deprecation_date=is_past_deprecation_date
@@ -187,18 +189,11 @@ _COST_MAP_DEPRECATION: Final = TypeAdapter(_CostMapDeprecation)
def _is_past_deprecation_date(cost_map_key: str) -> bool:
- deprecation_date: Final = _COST_MAP_DEPRECATION.validate_python(
- litellm.model_cost.get(cost_map_key) or {} # pyright: ignore[reportUnknownMemberType] # untyped cost map JSON
- ).get("deprecation_date")
- if not isinstance(deprecation_date, str):
- return False
- try:
- return (
- datetime.date.fromisoformat(deprecation_date)
- <= datetime.datetime.now(datetime.timezone.utc).astimezone().date()
+ return is_past_deprecation_date(
+ _COST_MAP_DEPRECATION.validate_python(
+ litellm.model_cost.get(cost_map_key) or {} # pyright: ignore[reportUnknownMemberType] # untyped cost map JSON
)
- except ValueError:
- return False
+ )
def _chat_row_costs(models: Iterable[str], custom_llm_provider: str) -> Iterator[tuple[str, float, bool]]:
diff --git a/litellm/litellm_core_utils/model_retirement.py b/litellm/litellm_core_utils/model_retirement.py
new file mode 100644
index 00000000000..3bfb834733d
--- /dev/null
+++ b/litellm/litellm_core_utils/model_retirement.py
@@ -0,0 +1,19 @@
+import datetime
+from collections.abc import Mapping
+from typing import Final
+
+PROVIDERS_HIDING_RETIRED_MODELS: Final = frozenset({"aiand", "baseten", "together_ai"})
+
+
+def is_past_deprecation_date(value: Mapping[str, object]) -> bool:
+ deprecation_date: Final = value.get("deprecation_date")
+ if not isinstance(deprecation_date, str):
+ return False
+ try:
+ return datetime.date.fromisoformat(deprecation_date) <= datetime.datetime.now(datetime.timezone.utc).date()
+ except ValueError:
+ return False
+
+
+def is_hidden_as_retired(value: Mapping[str, object]) -> bool:
+ return value.get("litellm_provider") in PROVIDERS_HIDING_RETIRED_MODELS and is_past_deprecation_date(value)
diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json
index e1131117fcf..ea9cacbdabe 100644
--- a/litellm/model_prices_and_context_window_backup.json
+++ b/litellm/model_prices_and_context_window_backup.json
@@ -72249,6 +72249,7 @@
},
"aiand/deepseek-ai/deepseek-v4-flash": {
"cache_read_input_token_cost": 8e-08,
+ "deprecation_date": "2026-10-27",
"input_cost_per_token": 1.5e-07,
"litellm_provider": "aiand",
"max_input_tokens": 1048576,
@@ -72278,6 +72279,22 @@
"supports_vision": false
},
"aiand/deepseek-ai/deepseek-v4.1-flash": {
+ "cache_read_input_token_cost": 2e-08,
+ "deprecation_date": "2026-11-05",
+ "input_cost_per_token": 3e-07,
+ "litellm_provider": "aiand",
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 384000,
+ "mode": "chat",
+ "output_cost_per_token": 6e-07,
+ "source": "https://api.aiand.com/v1/models",
+ "supports_function_calling": true,
+ "supports_prompt_caching": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true,
+ "supports_vision": true
+ },
+ "aiand/deepseek-ai/deepseek-v4.1-flash-1017": {
"cache_read_input_token_cost": 2e-08,
"input_cost_per_token": 3e-07,
"litellm_provider": "aiand",
@@ -72307,8 +72324,24 @@
"supports_tool_choice": true,
"supports_vision": true
},
+ "aiand/meta/muse-spark-open": {
+ "cache_read_input_token_cost": 1.5e-07,
+ "input_cost_per_token": 1.25e-06,
+ "litellm_provider": "aiand",
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 943718,
+ "mode": "chat",
+ "output_cost_per_token": 4.25e-06,
+ "source": "https://api.aiand.com/v1/models",
+ "supports_function_calling": true,
+ "supports_prompt_caching": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true,
+ "supports_vision": true
+ },
"aiand/moonshotai/kimi-k2.7-code": {
"cache_read_input_token_cost": 2e-07,
+ "deprecation_date": "2026-10-27",
"input_cost_per_token": 7.5e-07,
"litellm_provider": "aiand",
"max_input_tokens": 262144,
@@ -72399,6 +72432,7 @@
},
"aiand/zai-org/glm-5.2": {
"cache_read_input_token_cost": 3e-07,
+ "deprecation_date": "2026-10-27",
"input_cost_per_token": 1e-06,
"litellm_provider": "aiand",
"max_input_tokens": 1048576,
diff --git a/litellm/utils.py b/litellm/utils.py
index 6f56cc65f45..2ca8a49f968 100644
--- a/litellm/utils.py
+++ b/litellm/utils.py
@@ -94,6 +94,7 @@ from litellm.litellm_core_utils.fallback_generalizations import (
)
from litellm.litellm_core_utils.get_model_cost_map import AliasedCostEntry, GetModelCostMap
from litellm.litellm_core_utils.model_param_helper import peek_reasoning_summary_aliases
+from litellm.litellm_core_utils.model_retirement import is_hidden_as_retired
from litellm.litellm_core_utils.offline_mode import is_offline_mode
from litellm.litellm_core_utils.sensitive_data_masker import redact_credentials_in_payload
from litellm.litellm_core_utils.tokenizer import strip_special_tokens
@@ -8806,6 +8807,12 @@ def _get_valid_models_from_provider_api(
return []
+def bundled_provider_models(provider: str) -> tuple[str, ...]:
+ bundled: Final[tuple[str, ...]] = tuple(litellm.models_by_provider.get(provider, ()))
+ cost_map: Final = _builtin_cost_map()
+ return tuple(model for model in bundled if not is_hidden_as_retired(cost_map.get(model, {})))
+
+
def get_valid_models(
check_provider_endpoint: bool | None = None,
custom_llm_provider: str | None = None,
@@ -8871,8 +8878,7 @@ def get_valid_models(
)
)
else:
- models_for_provider = copy.deepcopy(litellm.models_by_provider.get(provider, []))
- valid_models.extend(models_for_provider)
+ valid_models.extend(bundled_provider_models(provider))
return valid_models
except Exception as e:
diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json
index e1131117fcf..ea9cacbdabe 100644
--- a/model_prices_and_context_window.json
+++ b/model_prices_and_context_window.json
@@ -72249,6 +72249,7 @@
},
"aiand/deepseek-ai/deepseek-v4-flash": {
"cache_read_input_token_cost": 8e-08,
+ "deprecation_date": "2026-10-27",
"input_cost_per_token": 1.5e-07,
"litellm_provider": "aiand",
"max_input_tokens": 1048576,
@@ -72278,6 +72279,22 @@
"supports_vision": false
},
"aiand/deepseek-ai/deepseek-v4.1-flash": {
+ "cache_read_input_token_cost": 2e-08,
+ "deprecation_date": "2026-11-05",
+ "input_cost_per_token": 3e-07,
+ "litellm_provider": "aiand",
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 384000,
+ "mode": "chat",
+ "output_cost_per_token": 6e-07,
+ "source": "https://api.aiand.com/v1/models",
+ "supports_function_calling": true,
+ "supports_prompt_caching": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true,
+ "supports_vision": true
+ },
+ "aiand/deepseek-ai/deepseek-v4.1-flash-1017": {
"cache_read_input_token_cost": 2e-08,
"input_cost_per_token": 3e-07,
"litellm_provider": "aiand",
@@ -72307,8 +72324,24 @@
"supports_tool_choice": true,
"supports_vision": true
},
+ "aiand/meta/muse-spark-open": {
+ "cache_read_input_token_cost": 1.5e-07,
+ "input_cost_per_token": 1.25e-06,
+ "litellm_provider": "aiand",
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 943718,
+ "mode": "chat",
+ "output_cost_per_token": 4.25e-06,
+ "source": "https://api.aiand.com/v1/models",
+ "supports_function_calling": true,
+ "supports_prompt_caching": true,
+ "supports_reasoning": true,
+ "supports_tool_choice": true,
+ "supports_vision": true
+ },
"aiand/moonshotai/kimi-k2.7-code": {
"cache_read_input_token_cost": 2e-07,
+ "deprecation_date": "2026-10-27",
"input_cost_per_token": 7.5e-07,
"litellm_provider": "aiand",
"max_input_tokens": 262144,
@@ -72399,6 +72432,7 @@
},
"aiand/zai-org/glm-5.2": {
"cache_read_input_token_cost": 3e-07,
+ "deprecation_date": "2026-10-27",
"input_cost_per_token": 1e-06,
"litellm_provider": "aiand",
"max_input_tokens": 1048576,
diff --git a/tests/unit/litellm_core_utils/test_llm_request_utils.py b/tests/unit/litellm_core_utils/test_llm_request_utils.py
index e7350fae395..5243d308543 100644
--- a/tests/unit/litellm_core_utils/test_llm_request_utils.py
+++ b/tests/unit/litellm_core_utils/test_llm_request_utils.py
@@ -1,3 +1,5 @@
+import datetime
+import time
from typing import Final
import httpx
@@ -245,3 +247,39 @@ def test_rank_chat_models_flags_a_retired_model_the_provider_lists_without_its_c
(ranked_model.model, ranked_model.is_past_deprecation_date)
for ranked_model in rank_chat_models_from_llm_provider("vertex_ai")
] == [("fake-retired-vertex-chat", True), ("fake-live-vertex-chat", False)]
+
+
+@pytest.mark.parametrize("host_zone", ["Etc/GMT+12", "Etc/GMT-14"])
+def test_rank_chat_models_flags_retirement_by_the_utc_date_whatever_the_host_zone(
+ monkeypatch: pytest.MonkeyPatch, host_zone: str
+) -> None:
+ utc_today: Final = datetime.datetime.now(datetime.timezone.utc).date()
+ retirement_dates: Final = {
+ "deepseek/fake-retires-today-chat": utc_today,
+ "deepseek/fake-retires-tomorrow-chat": utc_today + datetime.timedelta(days=1),
+ }
+ for name, retirement_date in retirement_dates.items():
+ monkeypatch.setitem(
+ litellm.model_cost,
+ name,
+ {
+ "input_cost_per_token": 1e-12,
+ "output_cost_per_token": 1e-12,
+ "mode": "chat",
+ "litellm_provider": PICKER_PROVIDER,
+ "deprecation_date": retirement_date.isoformat(),
+ },
+ )
+ monkeypatch.setitem(litellm.models_by_provider, PICKER_PROVIDER, tuple(retirement_dates))
+ monkeypatch.setenv("TZ", host_zone)
+ time.tzset()
+ try:
+ flags: Final = {
+ ranked_model.model: ranked_model.is_past_deprecation_date
+ for ranked_model in rank_chat_models_from_llm_provider(PICKER_PROVIDER)
+ }
+ finally:
+ monkeypatch.undo()
+ time.tzset()
+
+ assert flags == {"deepseek/fake-retires-today-chat": True, "deepseek/fake-retires-tomorrow-chat": False}
diff --git a/tests/unit/llms/baseten/chat/test_baseten_completions.py b/tests/unit/llms/baseten/chat/test_baseten_completions.py
index 4f135a1a106..407b39319e9 100644
--- a/tests/unit/llms/baseten/chat/test_baseten_completions.py
+++ b/tests/unit/llms/baseten/chat/test_baseten_completions.py
@@ -7,8 +7,9 @@ import pytest
import respx
import litellm
+from litellm.litellm_core_utils.model_retirement import is_past_deprecation_date
from litellm.llms.baseten.chat import BasetenConfig
-from litellm.utils import get_valid_models
+from litellm.utils import _model_cache, get_valid_models
class TestBasetenRouting:
@@ -65,7 +66,7 @@ class TestBasetenModelDiscovery:
servable_registry_models: Final = {
key
for key, value in litellm.model_cost.items()
- if value.get("litellm_provider") == "baseten" and not litellm._is_past_deprecation_date(value)
+ if value.get("litellm_provider") == "baseten" and not is_past_deprecation_date(value)
}
assert servable_registry_models
@@ -92,6 +93,20 @@ class TestBasetenModelDiscovery:
litellm.baseten_models.discard(model)
litellm.add_known_models({})
+ def test_wildcard_drops_a_model_whose_retirement_date_passes_while_running(self, monkeypatch: pytest.MonkeyPatch):
+ model: Final = "baseten/acme/retires-while-running"
+ monkeypatch.setitem(litellm.model_cost, model, {"litellm_provider": "baseten", "deprecation_date": "2999-01-01"})
+ try:
+ litellm.add_known_models({model: litellm.model_cost[model]})
+ assert model in get_valid_models(custom_llm_provider="baseten")
+
+ monkeypatch.setitem(litellm.model_cost, model, {"litellm_provider": "baseten", "deprecation_date": "2000-01-01"})
+
+ assert model not in get_valid_models(custom_llm_provider="baseten")
+ finally:
+ litellm.baseten_models.discard(model)
+ litellm.add_known_models({})
+
@pytest.mark.parametrize(
"value, expected",
[
@@ -102,7 +117,7 @@ class TestBasetenModelDiscovery:
],
)
def test_is_past_deprecation_date(self, value, expected):
- assert litellm._is_past_deprecation_date(value) is expected
+ assert is_past_deprecation_date(value) is expected
def test_get_models_calls_model_api(self, respx_mock: respx.MockRouter) -> None:
route: Final = respx_mock.get("https://inference.baseten.co/v1/models").mock(
@@ -156,6 +171,18 @@ class TestBasetenModelDiscovery:
assert models == ["baseten/brand-new/model"]
+ @patch.dict(os.environ, {"BASETEN_API_KEY": "test-key"})
+ def test_live_catalog_keeps_a_model_the_cost_map_dates_as_retired(self, respx_mock: respx.MockRouter) -> None:
+ assert is_past_deprecation_date(litellm.model_cost["baseten/zai-org/GLM-5"])
+ _model_cache.flush_cache()
+ respx_mock.get("https://inference.baseten.co/v1/models").mock(
+ return_value=httpx.Response(200, json={"data": [{"id": "zai-org/GLM-5"}]})
+ )
+
+ models: Final = get_valid_models(check_provider_endpoint=True, custom_llm_provider="baseten")
+
+ assert models == ["baseten/zai-org/GLM-5"]
+
class TestBasetenReasoningEffort:
def test_reasoning_effort_passthrough_with_drop_params(self):
diff --git a/tests/unit/llms/openai_like/test_aiand_provider.py b/tests/unit/llms/openai_like/test_aiand_provider.py
index 804f3a3b6eb..0274b58f19a 100644
--- a/tests/unit/llms/openai_like/test_aiand_provider.py
+++ b/tests/unit/llms/openai_like/test_aiand_provider.py
@@ -1,4 +1,6 @@
+import datetime
import json
+import time
from typing import Final
import httpx
@@ -8,6 +10,8 @@ import respx
import litellm
from litellm.caching.llm_caching_handler import LLMClientCache
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
+from litellm.litellm_core_utils.health_check_helpers import wildcard_health_check_models
+from litellm.litellm_core_utils.model_retirement import is_past_deprecation_date
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
from litellm.proxy.auth.model_checks import get_known_models_from_wildcard
from litellm.utils import ProviderConfigManager
@@ -89,11 +93,99 @@ def _aiand_catalog() -> frozenset[str]:
return frozenset(name for name, info in litellm.model_cost.items() if info.get("litellm_provider") == "aiand")
-def test_aiand_wildcard_lists_its_priced_models():
- catalog: Final = _aiand_catalog()
+def _utc_today() -> datetime.date:
+ return datetime.datetime.now(datetime.timezone.utc).date()
- assert catalog
- assert frozenset(get_known_models_from_wildcard("aiand/*")) == catalog
+
+def test_aiand_wildcard_lists_only_models_not_yet_retired():
+ catalog: Final = _aiand_catalog()
+ retired: Final = frozenset(
+ name
+ for name in catalog
+ if (retired_on := litellm.model_cost[name].get("deprecation_date")) is not None
+ and datetime.date.fromisoformat(retired_on) <= _utc_today()
+ )
+
+ assert catalog - retired
+ assert frozenset(get_known_models_from_wildcard("aiand/*")) == catalog - retired
+
+
+def test_aiand_wildcard_drops_a_model_whose_retirement_date_passes_while_running(monkeypatch: pytest.MonkeyPatch):
+ model: Final = "aiand/acme/retires-while-running"
+ monkeypatch.setitem(litellm.model_cost, model, {"litellm_provider": "aiand", "deprecation_date": "2999-01-01"})
+ try:
+ litellm.add_known_models({model: litellm.model_cost[model]})
+ assert model in get_known_models_from_wildcard("aiand/*")
+
+ monkeypatch.setitem(litellm.model_cost, model, {"litellm_provider": "aiand", "deprecation_date": "2000-01-01"})
+
+ assert model not in get_known_models_from_wildcard("aiand/*")
+ finally:
+ litellm.aiand_models.discard(model)
+ litellm.add_known_models({})
+
+
+def test_aiand_models_by_provider_leaves_out_models_retired_at_load():
+ retired: Final = frozenset(
+ name
+ for name, row in litellm.model_cost.items()
+ if row.get("litellm_provider") == "aiand" and is_past_deprecation_date(row)
+ )
+
+ assert retired
+ assert retired.isdisjoint(litellm.models_by_provider["aiand"])
+
+
+def test_aiand_wildcard_health_check_skips_a_model_whose_retirement_date_passes_while_running(
+ monkeypatch: pytest.MonkeyPatch,
+):
+ model: Final = "aiand/acme/free-and-retiring"
+ live_row: Final = {
+ "litellm_provider": "aiand",
+ "mode": "chat",
+ "input_cost_per_token": 0.0,
+ "output_cost_per_token": 0.0,
+ "deprecation_date": "2999-01-01",
+ }
+ monkeypatch.setitem(litellm.model_cost, model, live_row)
+ try:
+ litellm.add_known_models({model: live_row})
+ assert model in wildcard_health_check_models(wildcard="aiand/*", custom_llm_provider="aiand")
+
+ monkeypatch.setitem(litellm.model_cost, model, {**live_row, "deprecation_date": "2000-01-01"})
+
+ assert model not in wildcard_health_check_models(wildcard="aiand/*", custom_llm_provider="aiand")
+ finally:
+ litellm.aiand_models.discard(model)
+ litellm.add_known_models({})
+
+
+@pytest.mark.parametrize("host_zone", ["Etc/GMT+12", "Etc/GMT-14"])
+def test_aiand_models_retire_on_the_utc_date_whatever_the_host_zone(monkeypatch: pytest.MonkeyPatch, host_zone: str):
+ today: Final = _utc_today()
+ rows: Final = {
+ "aiand/acme/retires-today": {"litellm_provider": "aiand", "deprecation_date": today.isoformat()},
+ "aiand/acme/retires-tomorrow": {
+ "litellm_provider": "aiand",
+ "deprecation_date": (today + datetime.timedelta(days=1)).isoformat(),
+ },
+ }
+ for name, row in rows.items():
+ monkeypatch.setitem(litellm.model_cost, name, row)
+ monkeypatch.setenv("TZ", host_zone)
+ time.tzset()
+ try:
+ litellm.add_known_models(rows)
+ listed: Final = frozenset(get_known_models_from_wildcard("aiand/*"))
+
+ assert "aiand/acme/retires-today" not in listed
+ assert "aiand/acme/retires-tomorrow" in listed
+ finally:
+ monkeypatch.undo()
+ time.tzset()
+ for name in rows:
+ litellm.aiand_models.discard(name)
+ litellm.add_known_models({})
def test_aiand_calls_are_billed_from_their_cost_rows():
diff --git a/ui/litellm-dashboard/public/assets/logos/aiand.svg b/ui/litellm-dashboard/public/assets/logos/aiand.svg
new file mode 100644
index 00000000000..486c73b8dbc
--- /dev/null
+++ b/ui/litellm-dashboard/public/assets/logos/aiand.svg
@@ -0,0 +1,4 @@
+
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 810b010f25e..02c31ecc082 100644
--- a/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx
+++ b/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx
@@ -32,6 +32,18 @@ describe("provider_info_helpers", () => {
expect(getPlaceholder(Providers.BIGMODEL)).toMatch(/^bigmodel\//);
});
+ it("resolves ai& metadata, name, logo and model placeholder", () => {
+ const metadata = PROVIDER_CREATE_FIELDS.find((provider) => provider.provider === "AIAND");
+ expect(provider_map.AIAND).toBe(metadata?.litellm_provider);
+ expect(getProviderLogoAndName("aiand")).toEqual({
+ displayName: "ai&",
+ logo: providerLogoMap[Providers.AIAND],
+ });
+ expect(getProviderLogoAndName("AIAND")).toEqual(getProviderLogoAndName("aiand"));
+ expect(providerLogoMap[Providers.AIAND]).toContain("aiand");
+ expect(getPlaceholder(Providers.AIAND)).toBe("aiand/openai/gpt-oss-120b");
+ });
+
it("maps Microsoft 365 Copilot to its chat model provider and placeholder", () => {
expect(provider_map.MICROSOFT_365_COPILOT).toBe("microsoft_365_copilot");
expect(getPlaceholder(Providers.MICROSOFT_365_COPILOT)).toBe("microsoft_365_copilot/chat");
diff --git a/ui/litellm-dashboard/src/components/provider_info_helpers.tsx b/ui/litellm-dashboard/src/components/provider_info_helpers.tsx
index 1ed32c160e6..6448bd936cc 100644
--- a/ui/litellm-dashboard/src/components/provider_info_helpers.tsx
+++ b/ui/litellm-dashboard/src/components/provider_info_helpers.tsx
@@ -1,6 +1,7 @@
import { resolveLogoSrc } from "@/lib/assetPaths";
import a2aAgentLogo from "../../public/assets/logos/a2a_agent.png";
import ai21Logo from "../../public/assets/logos/ai21.svg";
+import aiandLogo from "../../public/assets/logos/aiand.svg";
import aimlApiLogo from "../../public/assets/logos/aiml_api.svg";
import anthropicLogo from "../../public/assets/logos/anthropic.svg";
import assemblyaiSmallLogo from "../../public/assets/logos/assemblyai_small.png";
@@ -76,6 +77,7 @@ export enum Providers {
A2A_Agent = "A2A Agent",
AI21 = "Ai21",
AI21_CHAT = "Ai21 Chat",
+ AIAND = "ai&",
AIML = "AI/ML API",
AIOHTTP_OPENAI = "Aiohttp Openai",
Anthropic = "Anthropic",
@@ -207,6 +209,7 @@ export const provider_map: Record = {
A2A_Agent: "a2a_agent",
AI21: "ai21",
AI21_CHAT: "ai21_chat",
+ AIAND: "aiand",
AIML: "aiml",
AIOHTTP_OPENAI: "aiohttp_openai",
Anthropic: "anthropic",
@@ -344,6 +347,7 @@ export const providerLogoMap: Partial> = {
[Providers.A2A_Agent]: a2aAgentLogo.src,
[Providers.AI21]: ai21Logo.src,
[Providers.AI21_CHAT]: ai21Logo.src,
+ [Providers.AIAND]: aiandLogo.src,
[Providers.AIML]: aimlApiLogo.src,
[Providers.AIOHTTP_OPENAI]: openaiSmallLogo.src,
[Providers.Anthropic]: anthropicLogo.src,
@@ -472,6 +476,7 @@ export const getProviderLogoAndName = (providerValue: string): { logo: string; d
const providerPlaceholderMap: Partial> = {
[Providers.AIML]: "aiml/flux-pro/v1.1",
+ [Providers.AIAND]: "aiand/openai/gpt-oss-120b",
[Providers.Anthropic]: "claude-3-opus",
[Providers.Azure]: "my-deployment",
[Providers.Azure_AI_Studio]: "azure_ai/command-r-plus",
diff --git a/ui/litellm-dashboard/src/lib/logoTreatments.ts b/ui/litellm-dashboard/src/lib/logoTreatments.ts
index fc19c5c364d..4cd6f65a613 100644
--- a/ui/litellm-dashboard/src/lib/logoTreatments.ts
+++ b/ui/litellm-dashboard/src/lib/logoTreatments.ts
@@ -32,6 +32,7 @@ const TREATMENT_BY_ASSET: Readonly> = {
"v0.svg": "invert",
"vercel.svg": "invert",
"watsonx.svg": "invert",
+ "aiand.svg": "plate",
"aiml_api.svg": "plate",
"akto.svg": "plate",
"aws.svg": "plate",