refactor(crusoe): simplify to JSON-based provider registration

Replace hand-written CrusoeChatConfig class and manual registrations
across constants.py, __init__.py, get_llm_provider_logic.py, and
_lazy_imports_registry.py with a single entry in
litellm/llms/openai_like/providers.json, consistent with the
recommended pattern for OpenAI-compatible providers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Emmanuel Acheampong 2026-03-12 14:15:44 -07:00
parent ab3ac4a8a0
commit b382650ec5
10 changed files with 130 additions and 140 deletions

View file

@ -577,7 +577,6 @@ publicai_models: Set = set()
v0_models: Set = set()
morph_models: Set = set()
lambda_ai_models: Set = set()
crusoe_models: Set = set()
hyperbolic_models: Set = set()
black_forest_labs_models: Set = set()
recraft_models: Set = set()
@ -825,8 +824,6 @@ def add_known_models(model_cost_map: Optional[Dict] = None):
morph_models.add(key)
elif value.get("litellm_provider") == "lambda_ai":
lambda_ai_models.add(key)
elif value.get("litellm_provider") == "crusoe":
crusoe_models.add(key)
elif value.get("litellm_provider") == "hyperbolic":
hyperbolic_models.add(key)
elif value.get("litellm_provider") == "black_forest_labs":
@ -1062,7 +1059,6 @@ models_by_provider: dict = {
"v0": v0_models,
"morph": morph_models,
"lambda_ai": lambda_ai_models,
"crusoe": crusoe_models,
"hyperbolic": hyperbolic_models,
"black_forest_labs": black_forest_labs_models,
"recraft": recraft_models,

View file

@ -1135,7 +1135,6 @@ _LLM_CONFIGS_IMPORT_MAP = {
"MorphChatConfig": (".llms.morph.chat.transformation", "MorphChatConfig"),
"RAGFlowConfig": (".llms.ragflow.chat.transformation", "RAGFlowConfig"),
"LambdaAIChatConfig": (".llms.lambda_ai.chat.transformation", "LambdaAIChatConfig"),
"CrusoeChatConfig": (".llms.crusoe.chat.transformation", "CrusoeChatConfig"),
"HyperbolicChatConfig": (
".llms.hyperbolic.chat.transformation",
"HyperbolicChatConfig",

View file

@ -560,7 +560,6 @@ LITELLM_CHAT_PROVIDERS = [
"oci",
"morph",
"lambda_ai",
"crusoe",
"vercel_ai_gateway",
"wandb",
"ovhcloud",
@ -719,7 +718,6 @@ openai_compatible_endpoints: List = [
"https://api.v0.dev/v1",
"https://api.morphllm.com/v1",
"https://api.lambda.ai/v1",
"https://managed-inference-api-proxy.crusoecloud.com/v1/",
"https://api.hyperbolic.xyz/v1",
"https://ai-gateway.helicone.ai/",
"https://ai-gateway.vercel.sh/v1",
@ -775,7 +773,6 @@ openai_compatible_providers: List = [
"helicone",
"morph",
"lambda_ai",
"crusoe",
"hyperbolic",
"vercel_ai_gateway",
"aiml",
@ -804,7 +801,6 @@ openai_text_completion_compatible_providers: List = (
"chutes",
"v0",
"lambda_ai",
"crusoe",
"hyperbolic",
"wandb",
]

View file

@ -315,9 +315,6 @@ def get_llm_provider( # noqa: PLR0915
elif endpoint == "https://api.lambda.ai/v1":
custom_llm_provider = "lambda_ai"
dynamic_api_key = get_secret_str("LAMBDA_API_KEY")
elif endpoint == "https://managed-inference-api-proxy.crusoecloud.com/v1/":
custom_llm_provider = "crusoe"
dynamic_api_key = get_secret_str("CRUSOE_API_KEY")
elif endpoint == "https://api.hyperbolic.xyz/v1":
custom_llm_provider = "hyperbolic"
dynamic_api_key = get_secret_str("HYPERBOLIC_API_KEY")
@ -883,13 +880,6 @@ def _get_openai_compatible_provider_info( # noqa: PLR0915
) = litellm.LambdaAIChatConfig()._get_openai_compatible_provider_info(
api_base, api_key
)
elif custom_llm_provider == "crusoe":
(
api_base,
dynamic_api_key,
) = litellm.CrusoeChatConfig()._get_openai_compatible_provider_info(
api_base, api_key
)
elif custom_llm_provider == "hyperbolic":
(
api_base,

View file

@ -1,42 +0,0 @@
"""
Translate from OpenAI's `/v1/chat/completions` to Crusoe's `/v1/chat/completions`
"""
from typing import Optional, Tuple
from litellm.secret_managers.main import get_secret_str
from ...openai_like.chat.transformation import OpenAILikeChatConfig
class CrusoeChatConfig(OpenAILikeChatConfig):
"""
Crusoe is OpenAI-compatible with standard endpoints.
Docs: https://docs.crusoecloud.com/managed-inference/overview/index.html
"""
@property
def custom_llm_provider(self) -> Optional[str]:
return "crusoe"
def _get_openai_compatible_provider_info(
self, api_base: Optional[str], api_key: Optional[str]
) -> Tuple[Optional[str], Optional[str]]:
api_base = (
api_base
or get_secret_str("CRUSOE_API_BASE")
or "https://managed-inference-api-proxy.crusoecloud.com/v1/"
) # type: ignore
dynamic_api_key = api_key or get_secret_str("CRUSOE_API_KEY")
return api_base, dynamic_api_key
def get_supported_openai_params(self, model: str) -> list:
return [
"messages",
"model",
"temperature",
"top_p",
"frequency_penalty",
"presence_penalty",
]

View file

@ -101,5 +101,10 @@
"param_mappings": {
"max_completion_tokens": "max_tokens"
}
},
"crusoe": {
"base_url": "https://managed-inference-api-proxy.crusoecloud.com/v1/",
"api_key_env": "CRUSOE_API_KEY",
"api_base_env": "CRUSOE_API_BASE"
}
}

View file

@ -4,24 +4,29 @@ Tests for Crusoe provider integration
import os
from unittest import mock
import pytest
import litellm
from litellm import completion
from litellm.llms.crusoe.chat.transformation import CrusoeChatConfig
CRUSOE_API_BASE = "https://managed-inference-api-proxy.crusoecloud.com/v1/"
def test_crusoe_config_initialization():
"""Test CrusoeChatConfig initializes correctly"""
config = CrusoeChatConfig()
assert config.custom_llm_provider == "crusoe"
def test_crusoe_json_registry():
"""Test CrusoeChatConfig is loaded from JSON provider registry"""
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
assert JSONProviderRegistry.exists("crusoe")
config = JSONProviderRegistry.get("crusoe")
assert config is not None
assert config.base_url == CRUSOE_API_BASE
assert config.api_key_env == "CRUSOE_API_KEY"
assert config.api_base_env == "CRUSOE_API_BASE"
def test_crusoe_get_openai_compatible_provider_info():
"""Test Crusoe provider info retrieval"""
config = CrusoeChatConfig()
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
config = create_config_class(JSONProviderRegistry.get("crusoe"))()
# Test with default values (no env vars set)
with mock.patch.dict(os.environ, {}, clear=True):
@ -67,22 +72,6 @@ def test_get_llm_provider_crusoe():
assert model == "meta-llama/Llama-3.3-70B-Instruct"
assert provider == "crusoe"
# Test with api_base containing Crusoe endpoint
model, provider, api_key, api_base = get_llm_provider(
"meta-llama/Llama-3.3-70B-Instruct",
api_base=CRUSOE_API_BASE,
)
assert model == "meta-llama/Llama-3.3-70B-Instruct"
assert provider == "crusoe"
assert api_base == CRUSOE_API_BASE
def test_crusoe_in_provider_lists():
"""Test that Crusoe is registered in all necessary provider lists"""
assert "crusoe" in litellm.openai_compatible_providers
assert "crusoe" in litellm.provider_list
assert CRUSOE_API_BASE in litellm.openai_compatible_endpoints
def test_crusoe_models_configuration():
"""Test that Crusoe models are configured correctly"""
@ -91,9 +80,6 @@ def test_crusoe_models_configuration():
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
litellm.crusoe_models = set()
litellm.add_known_models()
crusoe_models = [
"crusoe/meta-llama/Llama-3.3-70B-Instruct",
"crusoe/deepseek-ai/DeepSeek-R1-0528",
@ -111,54 +97,3 @@ def test_crusoe_models_configuration():
f"{model} should have crusoe as provider"
)
assert model_info.get("mode") == "chat", f"{model} should be in chat mode"
def test_crusoe_model_list_populated():
"""Test that crusoe_models list is populated correctly"""
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
litellm.crusoe_models = set()
litellm.add_known_models()
assert len(litellm.crusoe_models) > 0, "crusoe_models list should not be empty"
for model in litellm.crusoe_models:
assert model.startswith("crusoe/"), (
f"Model {model} should start with 'crusoe/'"
)
expected_models = [
"crusoe/meta-llama/Llama-3.3-70B-Instruct",
"crusoe/deepseek-ai/DeepSeek-R1-0528",
"crusoe/deepseek-ai/DeepSeek-V3-0324",
"crusoe/Qwen/Qwen3-235B-A22B-Instruct-2507",
"crusoe/moonshotai/Kimi-K2-Thinking",
"crusoe/openai/gpt-oss-120b",
"crusoe/google/gemma-3-12b-it",
]
for model in expected_models:
assert model in litellm.crusoe_models, (
f"{model} should be in crusoe_models list"
)
@pytest.mark.asyncio
async def test_crusoe_completion_call():
"""Test completion call with Crusoe provider (requires CRUSOE_API_KEY)"""
if not os.getenv("CRUSOE_API_KEY"):
pytest.skip("CRUSOE_API_KEY not set")
try:
response = await litellm.acompletion(
model="crusoe/meta-llama/Llama-3.3-70B-Instruct",
messages=[{"role": "user", "content": "Hello, this is a test"}],
max_tokens=10,
)
assert response.choices[0].message.content
assert response.model
assert response.usage
except Exception as e:
if "crusoe" not in str(e) and "provider" not in str(e).lower():
raise

View file

@ -0,0 +1,111 @@
import os
import sys
sys.path.insert(0, os.path.abspath("../../../../.."))
from unittest.mock import patch
CRUSOE_API_BASE = "https://managed-inference-api-proxy.crusoecloud.com/v1/"
def test_crusoe_json_registry():
"""Test Crusoe is registered in the JSON provider registry"""
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
assert JSONProviderRegistry.exists("crusoe")
config = JSONProviderRegistry.get("crusoe")
assert config is not None
assert config.base_url == CRUSOE_API_BASE
assert config.api_key_env == "CRUSOE_API_KEY"
assert config.api_base_env == "CRUSOE_API_BASE"
def test_crusoe_dynamic_config_defaults():
"""Test dynamic config returns correct default API base"""
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
config = create_config_class(JSONProviderRegistry.get("crusoe"))()
with patch.dict(os.environ, {}, clear=True):
api_base, api_key = config._get_openai_compatible_provider_info(None, None)
assert api_base == CRUSOE_API_BASE
assert api_key is None
def test_crusoe_dynamic_config_env_vars():
"""Test dynamic config reads CRUSOE_API_KEY and CRUSOE_API_BASE from env"""
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
config = create_config_class(JSONProviderRegistry.get("crusoe"))()
with patch.dict(
os.environ,
{"CRUSOE_API_KEY": "test-key", "CRUSOE_API_BASE": "https://custom.crusoe.com/v1/"},
):
api_base, api_key = config._get_openai_compatible_provider_info(None, None)
assert api_base == "https://custom.crusoe.com/v1/"
assert api_key == "test-key"
def test_crusoe_dynamic_config_explicit_params():
"""Test explicit params override env vars"""
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
config = create_config_class(JSONProviderRegistry.get("crusoe"))()
with patch.dict(os.environ, {"CRUSOE_API_KEY": "env-key"}):
api_base, api_key = config._get_openai_compatible_provider_info(
"https://override.crusoe.com/v1/", "override-key"
)
assert api_base == "https://override.crusoe.com/v1/"
assert api_key == "override-key"
def test_crusoe_supported_params():
"""Test dynamic config returns standard OpenAI params"""
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
config = create_config_class(JSONProviderRegistry.get("crusoe"))()
params = config.get_supported_openai_params(model="meta-llama/Llama-3.3-70B-Instruct")
assert isinstance(params, list)
assert len(params) > 0
assert "temperature" in params
assert "max_tokens" in params
assert "stream" in params
def test_crusoe_provider_detection_by_prefix():
"""Test crusoe/model prefix is correctly routed"""
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
model, provider, _, _ = get_llm_provider("crusoe/meta-llama/Llama-3.3-70B-Instruct")
assert provider == "crusoe"
assert model == "meta-llama/Llama-3.3-70B-Instruct"
def test_crusoe_model_list_populated():
"""Test Crusoe models are present in model_prices_and_context_window.json"""
import litellm
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
expected = [
"crusoe/meta-llama/Llama-3.3-70B-Instruct",
"crusoe/deepseek-ai/DeepSeek-R1-0528",
"crusoe/deepseek-ai/DeepSeek-V3-0324",
"crusoe/Qwen/Qwen3-235B-A22B-Instruct-2507",
"crusoe/moonshotai/Kimi-K2-Thinking",
"crusoe/openai/gpt-oss-120b",
"crusoe/google/gemma-3-12b-it",
]
for model in expected:
assert model in litellm.model_cost, f"{model} not found in model_cost"
assert litellm.model_cost[model].get("litellm_provider") == "crusoe"