diff --git a/litellm/__init__.py b/litellm/__init__.py index ff901ede512..ca64627ae89 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -724,6 +724,7 @@ transcribe_models: Set = set() gigachat_models: Set = set() llamagate_models: Set = set() coralbricks_models: Set[str] = set() +aiand_models: Set[str] = set() reducto_models: Set = set() bedrock_mantle_models: Set = set() @@ -1017,6 +1018,8 @@ def _populate_provider_model_sets(model_cost_map: Mapping[str, Mapping[str, obje llamagate_models.add(key) elif value.get("litellm_provider") == "coralbricks": coralbricks_models.add(key) + elif value.get("litellm_provider") == "aiand": + aiand_models.add(key) elif value.get("litellm_provider") == "reducto": reducto_models.add(key) elif value.get("litellm_provider") == "bedrock_mantle": @@ -1152,6 +1155,7 @@ model_list = list( | reducto_models | bedrock_mantle_models | coralbricks_models + | aiand_models | set(clarifai_models) ) @@ -1272,6 +1276,7 @@ def _build_models_by_provider() -> dict: "gigachat": gigachat_models, "llamagate": llamagate_models, "coralbricks": coralbricks_models, + "aiand": aiand_models, "reducto": reducto_models, "bedrock_mantle": bedrock_mantle_models, } diff --git a/litellm/provider_endpoints_support_backup.json b/litellm/provider_endpoints_support_backup.json index 9ff477f168e..aec94d01fbc 100644 --- a/litellm/provider_endpoints_support_backup.json +++ b/litellm/provider_endpoints_support_backup.json @@ -125,7 +125,7 @@ "url": "https://docs.aiand.com/api/chat-completions/", "endpoints": { "chat_completions": true, - "messages": false, + "messages": true, "responses": true, "embeddings": false, "image_generations": false, diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 93223876d28..8d65f17d8cd 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -126,7 +126,7 @@ "url": "https://docs.aiand.com/api/chat-completions/", "endpoints": { "chat_completions": true, - "messages": false, + "messages": true, "responses": true, "embeddings": false, "image_generations": false, diff --git a/tests/unit/llms/openai_like/test_aiand_provider.py b/tests/unit/llms/openai_like/test_aiand_provider.py index aaff5a7d96a..51586546ca9 100644 --- a/tests/unit/llms/openai_like/test_aiand_provider.py +++ b/tests/unit/llms/openai_like/test_aiand_provider.py @@ -1,4 +1,5 @@ import json +from typing import Final import httpx import pytest @@ -7,6 +8,7 @@ import respx import litellm from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider 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 AIAND_API_BASE = "https://api.aiand.com/v1" @@ -80,3 +82,27 @@ def test_aiand_responses_provider(): assert config is not None assert config.custom_llm_provider == "aiand" assert config.get_complete_url(api_base=None, litellm_params={}) == f"{AIAND_API_BASE}/responses" + + +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() + + assert catalog + assert frozenset(get_known_models_from_wildcard("aiand/*")) == catalog + + +def test_aiand_calls_are_billed_from_their_cost_rows(): + catalog: Final = _aiand_catalog() + assert catalog + + for model in sorted(catalog): + row: Final = litellm.model_cost[model] + prompt_cost, completion_cost = litellm.cost_per_token(model=model, prompt_tokens=1000, completion_tokens=500) + + assert prompt_cost == pytest.approx(1000 * row["input_cost_per_token"]) + assert completion_cost == pytest.approx(500 * row["output_cost_per_token"]) + assert prompt_cost > 0 and completion_cost > 0