fix(sampling): reject conflicting structural tag constraints (#32525)

This commit is contained in:
Mark
2026-08-02 20:24:55 -07:00
committed by GitHub
parent dd6ddc053b
commit 741e33db81
2 changed files with 27 additions and 14 deletions
@@ -196,9 +196,12 @@ class SamplingParams(msgspec.Struct, kw_only=True, array_like=True):
self.json_schema,
self.regex,
self.ebnf,
self.structural_tag,
] # since mutually exclusive, only one can be set
if sum(x is not None for x in grammars) > 1:
raise ValueError("Only one of regex, json_schema, or ebnf can be set.")
raise ValueError(
"Only one of json_schema, regex, ebnf, or structural_tag can be set."
)
def normalize(self, tokenizer):
# Process stop strings
@@ -77,6 +77,12 @@ class TestSamplingParamsInit(CustomTestCase):
class TestSamplingParamsVerify(CustomTestCase):
VOCAB_SIZE = 32000
GRAMMAR_VALUES = {
"json_schema": '{"type":"object"}',
"regex": "abc",
"ebnf": 'root ::= "abc"',
"structural_tag": '{"structures":[],"triggers":[]}',
}
def _make(self, **kwargs):
"""Helper: create SamplingParams with safe defaults, override with kwargs."""
@@ -273,21 +279,25 @@ class TestSamplingParamsVerify(CustomTestCase):
sp.verify(self.VOCAB_SIZE)
def test_multiple_grammars_raises(self):
"""Test that verify() rejects setting both json_schema and regex (mutually exclusive)."""
sp = self._make(json_schema='{"type":"object"}', regex="abc")
with self.assertRaises(ValueError):
sp.verify(self.VOCAB_SIZE)
"""Reject structural_tag combined with any other grammar constraint.
Constraint selection is a fixed if/elif chain, so a constraint left out of
this check is silently dropped with no error to the caller.
"""
for other in ("json_schema", "regex", "ebnf"):
with self.subTest(other=other):
sp = self._make(
structural_tag=self.GRAMMAR_VALUES["structural_tag"],
**{other: self.GRAMMAR_VALUES[other]},
)
with self.assertRaisesRegex(ValueError, "Only one of"):
sp.verify(self.VOCAB_SIZE)
def test_single_grammar_valid(self):
"""Test that setting only one grammar type is accepted."""
sp = self._make(json_schema='{"type":"object"}')
sp.verify(self.VOCAB_SIZE)
def test_all_three_grammars_set_raises(self):
"""Test that verify() rejects setting json_schema, regex, and ebnf together."""
sp = self._make(json_schema="{}", regex="a", ebnf="rule")
with self.assertRaises(ValueError):
sp.verify(self.VOCAB_SIZE)
"""Test that each grammar constraint is valid on its own."""
for grammar, value in self.GRAMMAR_VALUES.items():
with self.subTest(grammar=grammar):
self._make(**{grammar: value}).verify(self.VOCAB_SIZE)
class TestSamplingParamsNormalize(CustomTestCase):