mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
feat(ovhcloud): Add support of responses API (#22902)
* feat(ovhcloud): Add support of responses API * Edit from greptile recommendation * fix support of tool calling
This commit is contained in:
parent
bc781a06e5
commit
3c95588534
6 changed files with 221 additions and 0 deletions
|
|
@ -1449,6 +1449,7 @@ if TYPE_CHECKING:
|
|||
from .llms.perplexity.responses.transformation import PerplexityResponsesConfig as PerplexityResponsesConfig
|
||||
from .llms.databricks.responses.transformation import DatabricksResponsesAPIConfig as DatabricksResponsesAPIConfig
|
||||
from .llms.openrouter.responses.transformation import OpenRouterResponsesAPIConfig as OpenRouterResponsesAPIConfig
|
||||
from .llms.ovhcloud.responses.transformation import OVHCloudResponsesAPIConfig as OVHCloudResponsesAPIConfig
|
||||
from .llms.gemini.interactions.transformation import GoogleAIStudioInteractionsConfig as GoogleAIStudioInteractionsConfig
|
||||
from .llms.openai.chat.o_series_transformation import OpenAIOSeriesConfig as OpenAIOSeriesConfig, OpenAIOSeriesConfig as OpenAIO1Config
|
||||
from .llms.anthropic.skills.transformation import AnthropicSkillsConfig as AnthropicSkillsConfig
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ LLM_CONFIG_NAMES = (
|
|||
"PerplexityResponsesConfig",
|
||||
"DatabricksResponsesAPIConfig",
|
||||
"OpenRouterResponsesAPIConfig",
|
||||
"OVHCloudResponsesAPIConfig",
|
||||
"GoogleAIStudioInteractionsConfig",
|
||||
"OpenAIOSeriesConfig",
|
||||
"AnthropicSkillsConfig",
|
||||
|
|
@ -930,6 +931,10 @@ _LLM_CONFIGS_IMPORT_MAP = {
|
|||
".llms.openrouter.responses.transformation",
|
||||
"OpenRouterResponsesAPIConfig",
|
||||
),
|
||||
"OVHCloudResponsesAPIConfig": (
|
||||
".llms.ovhcloud.responses.transformation",
|
||||
"OVHCloudResponsesAPIConfig",
|
||||
),
|
||||
"GoogleAIStudioInteractionsConfig": (
|
||||
".llms.gemini.interactions.transformation",
|
||||
"GoogleAIStudioInteractionsConfig",
|
||||
|
|
|
|||
1
litellm/llms/ovhcloud/responses/__init__.py
Normal file
1
litellm/llms/ovhcloud/responses/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""OVHCloud Responses API support"""
|
||||
113
litellm/llms/ovhcloud/responses/transformation.py
Normal file
113
litellm/llms/ovhcloud/responses/transformation.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""
|
||||
Support for OVHcloud AI Endpoints `/v1/responses` endpoint.
|
||||
|
||||
Our unified API follows the OpenAI standard.
|
||||
More information on our website: https://oai.endpoints.kepler.ai.cloud.ovh.net/doc/gpt-oss-20b/openapi.json
|
||||
"""
|
||||
from typing import Optional
|
||||
import litellm
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig
|
||||
from litellm.secret_managers.main import get_secret_str
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
from litellm.types.utils import LlmProviders
|
||||
from litellm.utils import get_model_info
|
||||
|
||||
class OVHCloudResponsesAPIConfig(OpenAIResponsesAPIConfig):
|
||||
"""
|
||||
Configuration for OVHCloud AI Endpoints Responses API.
|
||||
|
||||
Inherits from OpenAIResponsesAPIConfig since OVHCloud's Responses API follows
|
||||
the OpenAI specification.
|
||||
|
||||
Reference: https://oai.endpoints.kepler.ai.cloud.ovh.net/doc/gpt-oss-20b/openapi.json
|
||||
"""
|
||||
|
||||
@property
|
||||
def custom_llm_provider(self) -> LlmProviders:
|
||||
return LlmProviders.OVHCLOUD
|
||||
|
||||
def get_supported_openai_params(self, model: str) -> list:
|
||||
"""
|
||||
Get supported OpenAI params, filtering tool-related params for models
|
||||
that don't support function calling.
|
||||
|
||||
Details about function calling support can be found here:
|
||||
https://help.ovhcloud.com/csm/en-gb-public-cloud-ai-endpoints-function-calling?id=kb_article_view&sysparm_article=KB0071907
|
||||
"""
|
||||
supported_params = super().get_supported_openai_params(model)
|
||||
|
||||
supports_function_calling: Optional[bool] = None
|
||||
try:
|
||||
model_info = get_model_info(model, custom_llm_provider="ovhcloud")
|
||||
supports_function_calling = model_info.get(
|
||||
"supports_function_calling", False
|
||||
)
|
||||
except Exception as e:
|
||||
verbose_logger.debug(f"Error getting supported OpenAI params: {e}")
|
||||
pass
|
||||
|
||||
if supports_function_calling is not True:
|
||||
verbose_logger.debug(
|
||||
"You can see our models supporting function_calling in our catalog: https://www.ovhcloud.com/en/public-cloud/ai-endpoints/catalog/ "
|
||||
)
|
||||
# Remove tool-related params for models that don't support function calling
|
||||
for param in ("tools", "tool_choice"):
|
||||
if param in supported_params:
|
||||
supported_params.remove(param)
|
||||
|
||||
return supported_params
|
||||
|
||||
def validate_environment(
|
||||
self, headers: dict, model: str, litellm_params: Optional[GenericLiteLLMParams]
|
||||
) -> dict:
|
||||
"""
|
||||
Validate environment and set up headers for OVHCloud API.
|
||||
|
||||
Uses OVHCLOUD_API_KEY from environment or litellm_params.
|
||||
"""
|
||||
litellm_params = litellm_params or GenericLiteLLMParams()
|
||||
api_key = (
|
||||
litellm_params.api_key
|
||||
or litellm.api_key
|
||||
or litellm.ovhcloud_key
|
||||
or get_secret_str("OVHCLOUD_API_KEY")
|
||||
)
|
||||
|
||||
if not api_key:
|
||||
raise ValueError(
|
||||
"OVHcloud AI Endpoints API key is required. Set OVHCLOUD_API_KEY environment variable or pass api_key parameter."
|
||||
)
|
||||
|
||||
headers.update(
|
||||
{
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
}
|
||||
)
|
||||
return headers
|
||||
|
||||
def get_complete_url(
|
||||
self,
|
||||
api_base: Optional[str],
|
||||
litellm_params: dict,
|
||||
) -> str:
|
||||
"""
|
||||
Get the complete URL for OVHcloud AI Endpoints Responses API endpoint.
|
||||
|
||||
Returns:
|
||||
str: The full URL for the OVHcloud AI Endpoints /v1/responses endpoint
|
||||
"""
|
||||
api_base = (
|
||||
api_base
|
||||
or litellm.api_base
|
||||
or get_secret_str("OVHCLOUD_API_BASE")
|
||||
or "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1"
|
||||
)
|
||||
|
||||
# Remove trailing slashes
|
||||
api_base = api_base.rstrip("/")
|
||||
|
||||
# Avoid double-appending /responses
|
||||
if not api_base.endswith("/responses"):
|
||||
return f"{api_base}/responses"
|
||||
return api_base
|
||||
|
|
@ -8353,6 +8353,8 @@ class ProviderConfigManager:
|
|||
return litellm.OpenRouterResponsesAPIConfig()
|
||||
elif litellm.LlmProviders.HOSTED_VLLM == provider:
|
||||
return litellm.HostedVLLMResponsesAPIConfig()
|
||||
elif litellm.LlmProviders.OVHCLOUD == provider:
|
||||
return litellm.OVHCloudResponsesAPIConfig()
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
"""
|
||||
Tests for OVHCloud Responses API transformation
|
||||
|
||||
Tests the OVHCloudResponsesAPIConfig class that handles OVHCloud-specific
|
||||
transformations for the Responses API.
|
||||
|
||||
Source: litellm/llms/ovhcloud/responses/transformation.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../../../../.."))
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.llms.ovhcloud.responses.transformation import OVHCloudResponsesAPIConfig
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
from litellm.types.utils import LlmProviders
|
||||
from litellm.utils import ProviderConfigManager
|
||||
|
||||
|
||||
class TestOVHCloudResponsesAPITransformation:
|
||||
"""Test OVHCloud Responses API configuration and transformations"""
|
||||
|
||||
def test_ovhcloud_provider_config_registration(self):
|
||||
"""Test that OVHCloud provider returns OVHCloudResponsesAPIConfig"""
|
||||
config = ProviderConfigManager.get_provider_responses_api_config(
|
||||
model="ovhcloud/gpt-oss-120b",
|
||||
provider=LlmProviders.OVHCLOUD,
|
||||
)
|
||||
|
||||
assert config is not None, "Config should not be None for OVHCloud provider"
|
||||
assert isinstance(
|
||||
config, OVHCloudResponsesAPIConfig
|
||||
), f"Expected OVHCloudResponsesAPIConfig, got {type(config)}"
|
||||
assert (
|
||||
config.custom_llm_provider == LlmProviders.OVHCLOUD
|
||||
), "custom_llm_provider should be OVHCLOUD"
|
||||
|
||||
def test_ovhcloud_responses_endpoint_url(self):
|
||||
"""Test that get_complete_url returns correct OVHCloud endpoint"""
|
||||
config = OVHCloudResponsesAPIConfig()
|
||||
|
||||
# Test with default OVHCloud API base
|
||||
url = config.get_complete_url(api_base=None, litellm_params={})
|
||||
assert url == "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1/responses", f"Expected OVHCloud responses endpoint, got {url}"
|
||||
|
||||
# Test with custom api_base
|
||||
custom_url = config.get_complete_url(
|
||||
api_base="https://custom.ovhcloud.example.com/v1",
|
||||
litellm_params={}
|
||||
)
|
||||
assert custom_url == "https://custom.ovhcloud.example.com/v1/responses", f"Expected custom endpoint, got {custom_url}"
|
||||
|
||||
# Test with trailing slash
|
||||
url_with_slash = config.get_complete_url(
|
||||
api_base="https://oai.endpoints.kepler.ai.cloud.ovh.net/v1/",
|
||||
litellm_params={}
|
||||
)
|
||||
assert url_with_slash == "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1/responses", "Should handle trailing slash"
|
||||
|
||||
def test_validate_environment_with_api_key(self):
|
||||
"""Test that validate_environment sets Authorization header correctly"""
|
||||
config = OVHCloudResponsesAPIConfig()
|
||||
|
||||
headers = {}
|
||||
litellm_params = GenericLiteLLMParams(api_key="test-api-key-123")
|
||||
|
||||
result = config.validate_environment(
|
||||
headers=headers,
|
||||
model="ovhcloud/gpt-oss-120b",
|
||||
litellm_params=litellm_params
|
||||
)
|
||||
|
||||
assert "Authorization" in result
|
||||
assert result["Authorization"] == "Bearer test-api-key-123"
|
||||
|
||||
def test_validate_environment_missing_api_key(self):
|
||||
"""Test that validate_environment raises error when API key is missing"""
|
||||
config = OVHCloudResponsesAPIConfig()
|
||||
|
||||
headers = {}
|
||||
|
||||
with pytest.raises(ValueError, match="OVHcloud AI Endpoints API key is required"):
|
||||
config.validate_environment(
|
||||
headers=headers,
|
||||
model="ovhcloud/gpt-oss-120b",
|
||||
litellm_params=None
|
||||
)
|
||||
|
||||
def test_supported_params_includes_openai_params(self):
|
||||
"""Test that get_supported_openai_params includes standard OpenAI params"""
|
||||
config = OVHCloudResponsesAPIConfig()
|
||||
supported = config.get_supported_openai_params("ovhcloud/gpt-oss-120b")
|
||||
|
||||
# OVHCloud follows OpenAI spec, so should support standard params
|
||||
assert "model" in supported, "model should be supported"
|
||||
assert "input" in supported, "input should be supported"
|
||||
assert "temperature" in supported, "temperature should be supported"
|
||||
Loading…
Add table
Reference in a new issue