From d77cf8115601f2856aacbfdd82a436ee78a558e6 Mon Sep 17 00:00:00 2001 From: Sriraj <168966222+sricursion@users.noreply.github.com> Date: Wed, 7 Oct 2026 05:51:00 +0530 Subject: [PATCH] [Bugfix][Frontend] Honor default penalties in batch chat completions (#60307) Signed-off-by: sricursion Co-authored-by: Flora Feng <4florafeng@gmail.com> --- .../openai/test_penalty_default_resolution.py | 28 ++++++++++++++++++- .../openai/chat_completion/protocol.py | 4 +-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/entrypoints/openai/test_penalty_default_resolution.py b/tests/entrypoints/openai/test_penalty_default_resolution.py index 2c39f5bef6..23c57241b7 100644 --- a/tests/entrypoints/openai/test_penalty_default_resolution.py +++ b/tests/entrypoints/openai/test_penalty_default_resolution.py @@ -2,7 +2,8 @@ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project """Unit tests for presence_penalty / frequency_penalty resolution from -default_sampling_params in ChatCompletionRequest and CompletionRequest. +default_sampling_params in ChatCompletionRequest, BatchChatCompletionRequest +and CompletionRequest. Regression test for https://github.com/vllm-project/vllm/issues/50767: these two penalties defaulted to 0.0 (not None) and to_sampling_params() @@ -12,6 +13,7 @@ discarded on the /v1/chat/completions and /v1/completions endpoints. """ from vllm.entrypoints.openai.chat_completion.protocol import ( + BatchChatCompletionRequest, ChatCompletionRequest, ) from vllm.entrypoints.openai.completion.protocol import ( @@ -29,6 +31,14 @@ def _chat(**kwargs): ) +def _batch(**kwargs): + conversation = [{"role": "user", "content": "hi"}] + request = BatchChatCompletionRequest( + model="test-model", messages=[conversation], **kwargs + ) + return request.to_chat_completion_request(conversation) + + class TestChatCompletionPenaltyDefaults: def test_defaults_applied_when_client_omits(self): """Server-default penalties are applied when the client sends none.""" @@ -49,6 +59,22 @@ class TestChatCompletionPenaltyDefaults: assert sp.frequency_penalty == 0.0 +class TestBatchChatCompletionPenaltyDefaults: + def test_defaults_applied_when_client_omits(self): + """Server-default penalties reach every conversation of a batch.""" + sp = _batch().to_sampling_params(100, _DEFAULTS) + assert sp.presence_penalty == 1.5 + assert sp.frequency_penalty == 0.5 + + def test_client_value_overrides_default(self): + """An explicit client penalty, even 0.0, wins over the server default.""" + sp = _batch(presence_penalty=0.0, frequency_penalty=0.2).to_sampling_params( + 100, _DEFAULTS + ) + assert sp.presence_penalty == 0.0 + assert sp.frequency_penalty == 0.2 + + class TestCompletionPenaltyDefaults: def test_defaults_applied_when_client_omits(self): sp = CompletionRequest(model="test-model", prompt="hi").to_sampling_params( diff --git a/vllm/entrypoints/openai/chat_completion/protocol.py b/vllm/entrypoints/openai/chat_completion/protocol.py index aee1c8a7a6..15905b8a3d 100644 --- a/vllm/entrypoints/openai/chat_completion/protocol.py +++ b/vllm/entrypoints/openai/chat_completion/protocol.py @@ -1093,7 +1093,7 @@ class BatchChatCompletionRequest(OpenAIBaseModel): model: str | None = None # Shared sampling / generation fields — mirror ChatCompletionRequest. - frequency_penalty: float | None = 0.0 + frequency_penalty: float | None = None logit_bias: dict[str, float] | None = None logprobs: bool | None = False top_logprobs: TopLogprobsParam = 0 @@ -1108,7 +1108,7 @@ class BatchChatCompletionRequest(OpenAIBaseModel): max_tokens: int | None = None max_completion_tokens: int | None = None n: int | None = 1 - presence_penalty: float | None = 0.0 + presence_penalty: float | None = None response_format: Any | None = None seed: int | None = Field(None, ge=_INT64_MIN, le=_INT64_MAX) stop: StopParam = Field(default_factory=list)