feat(provider): add Salad AI Gateway

This commit is contained in:
gorkii 2026-08-05 02:26:13 -04:00
parent 4fcaf7d736
commit fc3a52c49e
8 changed files with 179 additions and 0 deletions

View file

@ -736,6 +736,7 @@ openai_compatible_endpoints: Final[list] = [
"https://api.inference.wandb.ai/v1",
"https://api.clarifai.com/v2/ext/openai/v1",
"https://api.libertai.io/v1",
"https://ai.salad.cloud/v1",
"https://pinstripes.io/v1",
"https://api.meta.ai/v1",
]
@ -783,6 +784,7 @@ openai_compatible_providers: Final[list] = [
"chutes", # Chutes - JSON-configured provider
"parasail", # Parasail - JSON-configured provider
"libertai", # LibertAI - JSON-configured provider
"salad_cloud",
"featherless_ai",
"nscale",
"nebius",

View file

@ -159,6 +159,14 @@
"max_completion_tokens": "max_tokens"
}
},
"salad_cloud": {
"base_url": "https://ai.salad.cloud/v1",
"api_key_env": "SALAD_CLOUD_API_KEY",
"api_base_env": "SALAD_CLOUD_API_BASE",
"param_mappings": {
"max_completion_tokens": "max_tokens"
}
},
"empiriolabs": {
"base_url": "https://api.empiriolabs.ai/v1",
"api_key_env": "EMPIRIOLABS_API_KEY",

View file

@ -44210,6 +44210,23 @@
"supports_reasoning": true,
"source": "https://docs.libertai.io/apis/text/"
},
"salad_cloud/qwen3.6-35b-a3b": {
"max_tokens": 262144,
"max_input_tokens": 262144,
"max_output_tokens": 262144,
"input_cost_per_token": 9e-08,
"output_cost_per_token": 6e-07,
"litellm_provider": "salad_cloud",
"mode": "chat",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_system_messages": true,
"supports_vision": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_native_streaming": true,
"source": "https://docs.salad.com/ai-gateway/reference/models"
},
"libertai/qwen3.5-122b-a10b": {
"max_tokens": 262144,
"max_input_tokens": 262144,

View file

@ -1305,6 +1305,23 @@
"a2a": false
}
},
"salad_cloud": {
"display_name": "Salad AI Gateway (`salad_cloud`)",
"url": "https://docs.salad.com/ai-gateway/tutorials/getting-started",
"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
}
},
"litellm_proxy": {
"display_name": "LiteLLM Proxy (`litellm_proxy`)",
"url": "https://docs.litellm.ai/docs/providers/litellm_proxy",

View file

@ -3688,6 +3688,7 @@ class LlmProviders(str, Enum):
XIAOMI_MIMO = "xiaomi_mimo"
TENSORMESH = "tensormesh"
LIBERTAI = "libertai"
SALAD_CLOUD = "salad_cloud"
PINSTRIPES = "pinstripes"
DARKBLOOM = "darkbloom"
META = "meta"

View file

@ -44331,6 +44331,23 @@
"supports_reasoning": true,
"source": "https://docs.libertai.io/apis/text/"
},
"salad_cloud/qwen3.6-35b-a3b": {
"max_tokens": 262144,
"max_input_tokens": 262144,
"max_output_tokens": 262144,
"input_cost_per_token": 9e-08,
"output_cost_per_token": 6e-07,
"litellm_provider": "salad_cloud",
"mode": "chat",
"supports_function_calling": true,
"supports_tool_choice": true,
"supports_system_messages": true,
"supports_vision": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_native_streaming": true,
"source": "https://docs.salad.com/ai-gateway/reference/models"
},
"libertai/qwen3.5-122b-a10b": {
"max_tokens": 262144,
"max_input_tokens": 262144,

View file

@ -1420,6 +1420,23 @@
"a2a": false
}
},
"salad_cloud": {
"display_name": "Salad AI Gateway (`salad_cloud`)",
"url": "https://docs.salad.com/ai-gateway/tutorials/getting-started",
"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
}
},
"litellm_proxy": {
"display_name": "LiteLLM Proxy (`litellm_proxy`)",
"url": "https://docs.litellm.ai/docs/providers/litellm_proxy",

View file

@ -0,0 +1,100 @@
import litellm
class TestSaladCloudProviderConfig:
def test_provider_registration(self):
from litellm import LlmProviders
assert LlmProviders.SALAD_CLOUD.value == "salad_cloud"
assert "salad_cloud" in litellm.provider_list
def test_json_config(self):
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
assert JSONProviderRegistry.exists("salad_cloud")
provider = JSONProviderRegistry.get("salad_cloud")
assert provider is not None
assert provider.base_url == "https://ai.salad.cloud/v1"
assert provider.api_key_env == "SALAD_CLOUD_API_KEY"
assert provider.api_base_env == "SALAD_CLOUD_API_BASE"
assert provider.param_mappings.get("max_completion_tokens") == "max_tokens"
def test_provider_resolution(self):
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
model, provider, _, api_base = get_llm_provider(
model="salad_cloud/qwen3.6-35b-a3b",
custom_llm_provider=None,
api_base=None,
api_key=None,
)
assert model == "qwen3.6-35b-a3b"
assert provider == "salad_cloud"
assert api_base == "https://ai.salad.cloud/v1"
def test_api_base_override(self):
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
_, provider, api_key, api_base = get_llm_provider(
model="salad_cloud/qwen3.6-35b-a3b",
custom_llm_provider=None,
api_base="https://custom.example.com/v1",
api_key="test-key",
)
assert provider == "salad_cloud"
assert api_base == "https://custom.example.com/v1"
assert api_key == "test-key"
def test_model_metadata(self):
import json
from pathlib import Path
cost_map_path = (
Path(litellm.__file__).parent
/ "model_prices_and_context_window_backup.json"
)
info = json.loads(cost_map_path.read_text())["salad_cloud/qwen3.6-35b-a3b"]
assert info["litellm_provider"] == "salad_cloud"
assert info["mode"] == "chat"
assert info["max_input_tokens"] == 262144
assert info["max_output_tokens"] == 262144
assert info["input_cost_per_token"] == 0.09e-6
assert info["output_cost_per_token"] == 0.60e-6
assert info["supports_vision"] is True
assert info["supports_reasoning"] is True
assert info["supports_response_schema"] is True
assert info["supports_native_streaming"] is True
def test_router_config(self):
from litellm import Router
router = Router(
model_list=[
{
"model_name": "salad-chat",
"litellm_params": {
"model": "salad_cloud/qwen3.6-35b-a3b",
"api_key": "test-key",
},
}
]
)
assert router.model_list[0]["model_name"] == "salad-chat"
def test_supported_endpoints_matrix(self):
import json
from pathlib import Path
backup_path = (
Path(litellm.__file__).parent / "provider_endpoints_support_backup.json"
)
matrix = json.loads(backup_path.read_text())
endpoints = matrix["providers"]["salad_cloud"]["endpoints"]
assert endpoints["chat_completions"] is True
assert endpoints["messages"] is True
assert endpoints["responses"] is False