# 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., = 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