fix(hosted_vllm): forward provider-specific params in Responses API (closes #48362)

This commit is contained in:
HarshDubey23 2026-10-26 12:28:48 +05:30
parent dddbaa803d
commit 2ba1b5bf50
No known key found for this signature in database
3 changed files with 138 additions and 1 deletions

View file

@ -11,9 +11,32 @@ from typing import Final
from litellm.litellm_core_utils.url_utils import join_api_base
from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig
from litellm.secret_managers.main import get_secret_str
from litellm.types.llms.openai import ResponseInputParam
from litellm.types.router import GenericLiteLLMParams
from litellm.types.utils import LlmProviders
HOSTED_VLLM_RESPONSES_SUPPORTED_PARAMS: Final = (
"chat_template_kwargs",
"top_k",
"repetition_penalty",
"presence_penalty",
"frequency_penalty",
"min_p",
"best_of",
"stop_token_ids",
"spaces_between_special_tokens",
"prompt_logprobs",
"skip_special_tokens",
"include_stop_str_in_output",
"guided_json",
"guided_regex",
"guided_choice",
"guided_grammar",
"guided_decoding_backend",
"guided_whitespace_pattern",
"priority",
)
class HostedVLLMResponsesAPIConfig(OpenAIResponsesAPIConfig):
"""
@ -29,6 +52,41 @@ class HostedVLLMResponsesAPIConfig(OpenAIResponsesAPIConfig):
def custom_llm_provider(self) -> LlmProviders:
return LlmProviders.HOSTED_VLLM
def get_supported_openai_params(self, model: str) -> list[str]:
params = super().get_supported_openai_params(model)
params.extend(HOSTED_VLLM_RESPONSES_SUPPORTED_PARAMS)
return params
def transform_responses_api_request(
self,
model: str,
input: str | ResponseInputParam,
response_api_optional_request_params: dict,
litellm_params: GenericLiteLLMParams,
headers: dict,
) -> dict:
request: Final[dict] = super().transform_responses_api_request(
model=model,
input=input,
response_api_optional_request_params=response_api_optional_request_params,
litellm_params=litellm_params,
headers=headers,
)
for param in HOSTED_VLLM_RESPONSES_SUPPORTED_PARAMS:
if param in response_api_optional_request_params and response_api_optional_request_params[param] is not None:
request[param] = response_api_optional_request_params[param]
elif litellm_params is not None:
val = (
litellm_params.get(param)
if hasattr(litellm_params, "get")
else getattr(litellm_params, param, None)
)
if val is not None:
request[param] = val
return request
def validate_environment(
self,
headers: dict,

View file

@ -338,6 +338,14 @@ class ResponsesAPIRequestUtils:
custom_llm_provider: Final = params.pop("custom_llm_provider", None)
special_params: Final[dict[str, object]] = params.pop("kwargs", {})
allowed_openai_params: Final = (
params.get("allowed_openai_params")
or special_params.get("allowed_openai_params")
or []
)
allowed_set: Final = {p for p in allowed_openai_params if isinstance(p, str)}
default_keys: Final = set(valid_keys) | allowed_set
additional_drop_params: Final[list[str] | None] = params.pop("additional_drop_params", None)
non_default_params: Final = _apply_nested_drop_params(
PreProcessNonDefaultParams.base_pre_process_non_default_params(
@ -345,7 +353,7 @@ class ResponsesAPIRequestUtils:
special_params=special_params,
custom_llm_provider=custom_llm_provider,
additional_drop_params=additional_drop_params,
default_param_values={k: None for k in valid_keys},
default_param_values={k: None for k in default_keys},
additional_endpoint_specific_params=["input"],
),
additional_drop_params,

View file

@ -183,3 +183,74 @@ def test_hosted_vllm_validate_environment_custom_api_key():
)
assert headers.get("Authorization") == "Bearer my-custom-key"
def test_hosted_vllm_responses_supported_params():
"""Test get_supported_openai_params() includes vLLM provider-specific params."""
config = HostedVLLMResponsesAPIConfig()
supported = config.get_supported_openai_params(model="Qwen/Qwen3-8B")
assert "chat_template_kwargs" in supported
assert "top_k" in supported
assert "repetition_penalty" in supported
assert "presence_penalty" in supported
assert "frequency_penalty" in supported
assert "min_p" in supported
def test_hosted_vllm_responses_forwards_provider_specific_params():
"""
Regression test for Issue #48362:
hosted_vllm Responses API must not drop provider-specific params
(chat_template_kwargs, top_k, repetition_penalty, presence_penalty)
that chat completions forwards.
"""
mock_client = _make_mock_http_client(_make_mock_responses_api_response("Test output"))
with patch(
"litellm.llms.custom_httpx.llm_http_handler.get_httpx_client",
return_value=mock_client,
):
response = litellm.responses(
model="hosted_vllm/Qwen/Qwen3-8B",
input="hi",
api_base="https://test-vllm.example.com/v1",
api_key="test-key",
chat_template_kwargs={"enable_thinking": False},
top_k=20,
repetition_penalty=1.0,
presence_penalty=1.5,
)
assert response is not None
assert mock_client.post.call_count == 1
call_json = mock_client.post.call_args[1]["json"]
assert call_json["model"] == "Qwen/Qwen3-8B"
assert call_json["input"] == "hi"
assert call_json["chat_template_kwargs"] == {"enable_thinking": False}
assert call_json["top_k"] == 20
assert call_json["repetition_penalty"] == 1.0
assert call_json["presence_penalty"] == 1.5
def test_hosted_vllm_responses_transform_request_from_litellm_params():
"""Test transform_responses_api_request forwards provider params from litellm_params."""
config = HostedVLLMResponsesAPIConfig()
litellm_params = GenericLiteLLMParams(
chat_template_kwargs={"enable_thinking": False},
top_k=50,
min_p=0.05,
)
request = config.transform_responses_api_request(
model="Qwen/Qwen3-8B",
input="test input",
response_api_optional_request_params={},
litellm_params=litellm_params,
headers={},
)
assert request["chat_template_kwargs"] == {"enable_thinking": False}
assert request["top_k"] == 50
assert request["min_p"] == 0.05