fix(frontend): bound stop strings and regex patterns (#37029)

This commit is contained in:
EchO
2026-08-29 22:25:26 -07:00
committed by GitHub
parent 78fa921189
commit 5b7c62d5d6
2 changed files with 60 additions and 0 deletions
@@ -38,6 +38,9 @@ CustomParamValue = Union[
_SAMPLING_EPS = 1e-6
TOP_K_ALL = 1 << 30
MAX_STOP_COUNT = 32
MAX_STOP_REGEX_LEN = 256
MAX_STOP_REGEX_COUNT = 32
logger = logging.getLogger(__name__)
@@ -222,6 +225,11 @@ class SamplingParams(msgspec.Struct, kw_only=True, array_like=True):
else:
if isinstance(self.stop_strs, str):
self.stop_strs = [self.stop_strs]
if len(self.stop_strs) > MAX_STOP_COUNT:
raise ValueError(
f"at most {MAX_STOP_COUNT} stop strings are allowed, "
f"got {len(self.stop_strs)}"
)
stop_str_max_len = 0
for stop_str in self.stop_strs:
@@ -239,9 +247,20 @@ class SamplingParams(msgspec.Struct, kw_only=True, array_like=True):
else:
if isinstance(self.stop_regex_strs, str):
self.stop_regex_strs = [self.stop_regex_strs]
if len(self.stop_regex_strs) > MAX_STOP_REGEX_COUNT:
raise ValueError(
f"at most {MAX_STOP_REGEX_COUNT} stop_regex patterns are allowed, "
f"got {len(self.stop_regex_strs)}"
)
stop_regex_max_len = 0
for stop_regex in self.stop_regex_strs:
stop_regex_len = len(stop_regex.encode("utf-8"))
if stop_regex_len > MAX_STOP_REGEX_LEN:
raise ValueError(
f"stop_regex is {stop_regex_len} bytes, over the "
f"{MAX_STOP_REGEX_LEN}-byte limit"
)
stop_regex_max_len = max(
stop_regex_max_len, get_max_seq_length(stop_regex)
)
@@ -14,6 +14,9 @@ import msgspec
from sglang.srt.sampling.sampling_params import (
MAX_LEN,
MAX_STOP_COUNT,
MAX_STOP_REGEX_COUNT,
MAX_STOP_REGEX_LEN,
TOP_K_ALL,
SamplingParams,
get_max_seq_length,
@@ -344,6 +347,17 @@ class TestSamplingParamsNormalize(CustomTestCase):
sp.normalize(tokenizer=tokenizer)
self.assertEqual(sp.stop_strs, ["stop1", "stop2"])
def test_stop_count_limit(self):
tokenizer = self._mock_tokenizer()
SamplingParams(stop=["x"] * MAX_STOP_COUNT).normalize(tokenizer)
with self.assertRaises(ValueError) as cm:
SamplingParams(stop=["x"] * (MAX_STOP_COUNT + 1)).normalize(tokenizer)
self.assertEqual(
str(cm.exception),
f"at most {MAX_STOP_COUNT} stop strings are allowed, got {MAX_STOP_COUNT + 1}",
)
def test_stop_str_max_len_uses_encoded_length(self):
"""Test that max_len is based on encoded token count, not character count."""
# "ab" encodes to 1 token, "cdef" encodes to 2 tokens
@@ -385,6 +399,33 @@ class TestSamplingParamsNormalize(CustomTestCase):
sp.normalize(tokenizer=tokenizer)
self.assertEqual(sp.stop_regex_max_len, 3)
def test_stop_regex_count_limit(self):
tokenizer = self._mock_tokenizer()
SamplingParams(stop_regex=["x"] * MAX_STOP_REGEX_COUNT).normalize(tokenizer)
with self.assertRaises(ValueError) as cm:
SamplingParams(stop_regex=["x"] * (MAX_STOP_REGEX_COUNT + 1)).normalize(
tokenizer
)
self.assertEqual(
str(cm.exception),
f"at most {MAX_STOP_REGEX_COUNT} stop_regex patterns are allowed, "
f"got {MAX_STOP_REGEX_COUNT + 1}",
)
def test_stop_regex_byte_length_limit(self):
tokenizer = self._mock_tokenizer()
pattern = "é" * (MAX_STOP_REGEX_LEN // 2)
SamplingParams(stop_regex=pattern).normalize(tokenizer)
with self.assertRaises(ValueError) as cm:
SamplingParams(stop_regex=pattern + "a").normalize(tokenizer)
self.assertEqual(
str(cm.exception),
f"stop_regex is {MAX_STOP_REGEX_LEN + 1} bytes, over the "
f"{MAX_STOP_REGEX_LEN}-byte limit",
)
class TestSamplingParamsMsgspecStruct(CustomTestCase):