161 lines
5.6 KiB
Python
161 lines
5.6 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
"""
|
|
Unit tests for stop_token_ids propagation from default_sampling_params
|
|
to SamplingParams in ChatCompletionRequest and CompletionRequest.
|
|
|
|
Regression test for https://github.com/vllm-project/vllm/issues/22519
|
|
where gpt-oss model stop tokens (e.g., </call> = 200012) were loaded into
|
|
default_sampling_params at server startup but silently discarded on every
|
|
request because to_sampling_params() never fell back to defaults.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from vllm.entrypoints.openai.chat_completion.protocol import (
|
|
ChatCompletionRequest,
|
|
)
|
|
from vllm.entrypoints.openai.completion.protocol import (
|
|
CompletionRequest,
|
|
)
|
|
|
|
|
|
class TestChatCompletionStopTokenIds:
|
|
"""Test stop_token_ids merging in ChatCompletionRequest.to_sampling_params()."""
|
|
|
|
@pytest.fixture
|
|
def minimal_chat_request(self):
|
|
return ChatCompletionRequest(
|
|
model="test-model",
|
|
messages=[{"role": "user", "content": "hello"}],
|
|
)
|
|
|
|
def test_default_stop_token_ids_applied(self, minimal_chat_request):
|
|
"""Server-default stop_token_ids are applied when client sends none."""
|
|
default_sampling_params = {
|
|
"stop_token_ids": [200012, 200002],
|
|
}
|
|
|
|
sampling_params = minimal_chat_request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params=default_sampling_params,
|
|
)
|
|
|
|
assert set(sampling_params.stop_token_ids) == {200012, 200002}
|
|
|
|
def test_client_stop_token_ids_merged_with_defaults(self):
|
|
"""Client-specified stop_token_ids are merged with server defaults."""
|
|
request = ChatCompletionRequest(
|
|
model="test-model",
|
|
messages=[{"role": "user", "content": "hello"}],
|
|
stop_token_ids=[99999],
|
|
)
|
|
default_sampling_params = {
|
|
"stop_token_ids": [200012, 200002],
|
|
}
|
|
|
|
sampling_params = request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params=default_sampling_params,
|
|
)
|
|
|
|
assert set(sampling_params.stop_token_ids) == {200012, 200002, 99999}
|
|
assert sampling_params.stop_token_ids == [99999, 200012, 200002]
|
|
|
|
def test_no_stop_token_ids_anywhere(self, minimal_chat_request):
|
|
"""When neither client nor server specifies stop_token_ids, result is empty."""
|
|
sampling_params = minimal_chat_request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params={},
|
|
)
|
|
|
|
assert not sampling_params.stop_token_ids
|
|
|
|
def test_only_client_stop_token_ids(self):
|
|
"""Client stop_token_ids work when no server defaults exist."""
|
|
request = ChatCompletionRequest(
|
|
model="test-model",
|
|
messages=[{"role": "user", "content": "hello"}],
|
|
stop_token_ids=[42, 43],
|
|
)
|
|
|
|
sampling_params = request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params={},
|
|
)
|
|
|
|
assert set(sampling_params.stop_token_ids) == {42, 43}
|
|
|
|
def test_duplicate_stop_token_ids_deduplicated(self):
|
|
"""Overlapping stop_token_ids between client and server are deduplicated."""
|
|
request = ChatCompletionRequest(
|
|
model="test-model",
|
|
messages=[{"role": "user", "content": "hello"}],
|
|
stop_token_ids=[200012, 55555],
|
|
)
|
|
default_sampling_params = {
|
|
"stop_token_ids": [200012, 200002],
|
|
}
|
|
|
|
sampling_params = request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params=default_sampling_params,
|
|
)
|
|
|
|
assert set(sampling_params.stop_token_ids) == {200012, 200002, 55555}
|
|
assert sampling_params.stop_token_ids == [200012, 55555, 200002]
|
|
assert len(sampling_params.stop_token_ids) == 3
|
|
|
|
|
|
class TestCompletionStopTokenIds:
|
|
"""Test stop_token_ids merging in CompletionRequest.to_sampling_params()."""
|
|
|
|
@pytest.fixture
|
|
def minimal_completion_request(self):
|
|
return CompletionRequest(
|
|
model="test-model",
|
|
prompt="hello",
|
|
)
|
|
|
|
def test_default_stop_token_ids_applied(self, minimal_completion_request):
|
|
"""Server-default stop_token_ids are applied when client sends none."""
|
|
default_sampling_params = {
|
|
"stop_token_ids": [200012, 200002],
|
|
}
|
|
|
|
sampling_params = minimal_completion_request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params=default_sampling_params,
|
|
)
|
|
|
|
assert set(sampling_params.stop_token_ids) == {200012, 200002}
|
|
|
|
def test_client_stop_token_ids_merged_with_defaults(self):
|
|
"""Client-specified stop_token_ids are merged with server defaults."""
|
|
request = CompletionRequest(
|
|
model="test-model",
|
|
prompt="hello",
|
|
stop_token_ids=[99999],
|
|
)
|
|
default_sampling_params = {
|
|
"stop_token_ids": [200012, 200002],
|
|
}
|
|
|
|
sampling_params = request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params=default_sampling_params,
|
|
)
|
|
|
|
assert set(sampling_params.stop_token_ids) == {200012, 200002, 99999}
|
|
assert sampling_params.stop_token_ids == [99999, 200012, 200002]
|
|
|
|
def test_no_stop_token_ids_anywhere(self, minimal_completion_request):
|
|
"""When neither client nor server specifies stop_token_ids, result is empty."""
|
|
sampling_params = minimal_completion_request.to_sampling_params(
|
|
max_tokens=100,
|
|
default_sampling_params={},
|
|
)
|
|
|
|
assert not sampling_params.stop_token_ids
|