mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-26 01:12:21 +00:00
fix(openai-like): drop unsupported Xiaomi output config
This commit is contained in:
parent
57e5e4a3b7
commit
805d3cd45e
4 changed files with 159 additions and 1 deletions
|
|
@ -10,6 +10,7 @@ from typing import Any, Callable, Optional, Union
|
|||
import httpx
|
||||
|
||||
import litellm
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm import LlmProviders
|
||||
from litellm.llms.bedrock.chat.invoke_handler import MockResponseIterator
|
||||
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler
|
||||
|
|
@ -20,6 +21,7 @@ from litellm.types.utils import CustomStreamingDecoder, ModelResponse
|
|||
from litellm.utils import CustomStreamWrapper, ProviderConfigManager
|
||||
|
||||
from ..common_utils import OpenAILikeBase, OpenAILikeError
|
||||
from ..json_loader import JSONProviderRegistry
|
||||
from .transformation import OpenAILikeChatConfig
|
||||
|
||||
|
||||
|
|
@ -112,6 +114,25 @@ class OpenAILikeChatHandler(OpenAILikeBase):
|
|||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@staticmethod
|
||||
def _drop_provider_unsupported_params(
|
||||
custom_llm_provider: str, optional_params: dict, extra_body: dict
|
||||
) -> None:
|
||||
provider = JSONProviderRegistry.get(custom_llm_provider)
|
||||
if provider is None:
|
||||
return
|
||||
|
||||
for param in provider.unsupported_params:
|
||||
removed_optional_param = optional_params.pop(param, None)
|
||||
removed_extra_body_param = extra_body.pop(param, None)
|
||||
if (
|
||||
removed_optional_param is not None
|
||||
or removed_extra_body_param is not None
|
||||
):
|
||||
verbose_logger.debug(
|
||||
f"Dropping unsupported param '{param}' for provider '{custom_llm_provider}'"
|
||||
)
|
||||
|
||||
async def acompletion_stream_function(
|
||||
self,
|
||||
model: str,
|
||||
|
|
@ -254,9 +275,14 @@ class OpenAILikeChatHandler(OpenAILikeBase):
|
|||
)
|
||||
|
||||
stream: bool = optional_params.pop("stream", None) or False
|
||||
extra_body = optional_params.pop("extra_body", {})
|
||||
extra_body = optional_params.pop("extra_body", {}) or {}
|
||||
json_mode = optional_params.pop("json_mode", None)
|
||||
optional_params.pop("max_retries", None)
|
||||
self._drop_provider_unsupported_params(
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
optional_params=optional_params,
|
||||
extra_body=extra_body,
|
||||
)
|
||||
if not fake_stream:
|
||||
optional_params["stream"] = stream
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class SimpleProviderConfig:
|
|||
self.param_mappings = data.get("param_mappings", {})
|
||||
self.constraints = data.get("constraints", {})
|
||||
self.special_handling = data.get("special_handling", {})
|
||||
self.unsupported_params = data.get("unsupported_params", [])
|
||||
self.supported_endpoints = data.get("supported_endpoints", [])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
"xiaomi_mimo": {
|
||||
"base_url": "https://api.xiaomimimo.com/v1",
|
||||
"api_key_env": "XIAOMI_MIMO_API_KEY",
|
||||
"unsupported_params": [
|
||||
"output_config"
|
||||
],
|
||||
"param_mappings": {
|
||||
"max_completion_tokens": "max_tokens"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Related to issue #18794
|
|||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
|
@ -46,6 +47,7 @@ class TestXiaomiMiMoProviderConfig:
|
|||
assert xiaomi_mimo.base_url == "https://api.xiaomimimo.com/v1"
|
||||
assert xiaomi_mimo.api_key_env == "XIAOMI_MIMO_API_KEY"
|
||||
assert xiaomi_mimo.param_mappings.get("max_completion_tokens") == "max_tokens"
|
||||
assert "output_config" in xiaomi_mimo.unsupported_params
|
||||
|
||||
def test_xiaomi_mimo_provider_resolution(self):
|
||||
"""Test that provider resolution finds xiaomi_mimo"""
|
||||
|
|
@ -83,6 +85,132 @@ class TestXiaomiMiMoProviderConfig:
|
|||
assert len(router.model_list) == 1
|
||||
assert router.model_list[0]["model_name"] == "mimo-v2-flash"
|
||||
|
||||
def test_xiaomi_mimo_drops_output_config_from_request_body(self):
|
||||
"""Xiaomi MiMo rejects Claude-only output_config; do not forward it."""
|
||||
from litellm.llms.custom_httpx.http_handler import HTTPHandler
|
||||
from litellm.llms.openai_like.chat.handler import OpenAILikeChatHandler
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
client = HTTPHandler()
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.headers = {"content-type": "application/json"}
|
||||
mock_response.json.return_value = {
|
||||
"id": "chatcmpl-test",
|
||||
"object": "chat.completion",
|
||||
"created": 0,
|
||||
"model": "mimo-v2-flash",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"message": {"role": "assistant", "content": "ok"},
|
||||
"finish_reason": "stop",
|
||||
}
|
||||
],
|
||||
"usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
|
||||
}
|
||||
mock_response.raise_for_status.return_value = None
|
||||
|
||||
logging_obj = MagicMock()
|
||||
logging_obj.model_call_details = {}
|
||||
|
||||
with patch.object(client, "post", return_value=mock_response) as mock_post:
|
||||
OpenAILikeChatHandler().completion(
|
||||
model="mimo-v2-flash",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
api_base="https://api.xiaomimimo.com/v1",
|
||||
custom_llm_provider="xiaomi_mimo",
|
||||
custom_prompt_dict={},
|
||||
model_response=ModelResponse(),
|
||||
print_verbose=lambda *args, **kwargs: None,
|
||||
encoding=None,
|
||||
api_key="test-key",
|
||||
logging_obj=logging_obj,
|
||||
optional_params={
|
||||
"output_config": {"effort": "medium"},
|
||||
"extra_body": {"output_config": {"effort": "medium"}},
|
||||
},
|
||||
client=client,
|
||||
)
|
||||
|
||||
request_body = json.loads(mock_post.call_args.kwargs["data"])
|
||||
assert "output_config" not in request_body
|
||||
assert request_body["model"] == "mimo-v2-flash"
|
||||
assert request_body["messages"] == [{"role": "user", "content": "hi"}]
|
||||
|
||||
def test_xiaomi_mimo_handles_none_extra_body(self):
|
||||
"""An explicit extra_body=None should not break unsupported-param filtering."""
|
||||
from litellm.llms.custom_httpx.http_handler import HTTPHandler
|
||||
from litellm.llms.openai_like.chat.handler import OpenAILikeChatHandler
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
client = HTTPHandler()
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.headers = {"content-type": "application/json"}
|
||||
mock_response.json.return_value = {
|
||||
"id": "chatcmpl-test",
|
||||
"object": "chat.completion",
|
||||
"created": 0,
|
||||
"model": "mimo-v2-flash",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"message": {"role": "assistant", "content": "ok"},
|
||||
"finish_reason": "stop",
|
||||
}
|
||||
],
|
||||
"usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
|
||||
}
|
||||
mock_response.raise_for_status.return_value = None
|
||||
|
||||
logging_obj = MagicMock()
|
||||
logging_obj.model_call_details = {}
|
||||
|
||||
with patch.object(client, "post", return_value=mock_response) as mock_post:
|
||||
OpenAILikeChatHandler().completion(
|
||||
model="mimo-v2-flash",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
api_base="https://api.xiaomimimo.com/v1",
|
||||
custom_llm_provider="xiaomi_mimo",
|
||||
custom_prompt_dict={},
|
||||
model_response=ModelResponse(),
|
||||
print_verbose=lambda *args, **kwargs: None,
|
||||
encoding=None,
|
||||
api_key="test-key",
|
||||
logging_obj=logging_obj,
|
||||
optional_params={
|
||||
"extra_body": None,
|
||||
"output_config": {"effort": "medium"},
|
||||
},
|
||||
client=client,
|
||||
)
|
||||
|
||||
request_body = json.loads(mock_post.call_args.kwargs["data"])
|
||||
assert "output_config" not in request_body
|
||||
assert request_body["model"] == "mimo-v2-flash"
|
||||
|
||||
def test_xiaomi_mimo_logs_dropped_output_config(self):
|
||||
"""Dropped provider params should be observable in debug logs."""
|
||||
from litellm.llms.openai_like.chat.handler import OpenAILikeChatHandler
|
||||
|
||||
optional_params = {"output_config": {"effort": "medium"}}
|
||||
extra_body = {}
|
||||
|
||||
with patch(
|
||||
"litellm.llms.openai_like.chat.handler.verbose_logger.debug"
|
||||
) as mock_debug:
|
||||
OpenAILikeChatHandler._drop_provider_unsupported_params(
|
||||
custom_llm_provider="xiaomi_mimo",
|
||||
optional_params=optional_params,
|
||||
extra_body=extra_body,
|
||||
)
|
||||
|
||||
assert optional_params == {}
|
||||
mock_debug.assert_called_once_with(
|
||||
"Dropping unsupported param 'output_config' for provider 'xiaomi_mimo'"
|
||||
)
|
||||
|
||||
|
||||
class TestXiaomiMiMoIntegration:
|
||||
"""Integration tests for Xiaomi MiMo provider"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue