# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project """Request-time validation of structured output requests.""" import pytest from vllm.config import StructuredOutputsConfig from vllm.sampling_params import SamplingParams, StructuredOutputsParams pytestmark = pytest.mark.cpu_test JSON_SCHEMA = { "type": "object", "properties": { "invoice_id": {"type": "string"}, "customer": {"type": "string"}, }, "required": ["invoice_id", "customer"], "additionalProperties": False, } class _StubModelConfig: def __init__(self, is_diffusion: bool): self.is_diffusion = is_diffusion def test_structured_outputs_rejected_for_diffusion_models(): """Diffusion LLMs denoise the canvas in parallel, which is incompatible with the token-by-token grammar FSM. The request must fail with a clear validation error instead of an FSM rejection mid-generation (#45436).""" params = SamplingParams( structured_outputs=StructuredOutputsParams(json=JSON_SCHEMA) ) with pytest.raises(ValueError, match="not yet supported for diffusion"): params._validate_structured_outputs( _StubModelConfig(is_diffusion=True), StructuredOutputsConfig(), tokenizer=None, ) def test_plain_request_allowed_for_diffusion_models(): """Requests without structured outputs are unaffected by the guard.""" params = SamplingParams() params._validate_structured_outputs( _StubModelConfig(is_diffusion=True), StructuredOutputsConfig(), tokenizer=None, ) @pytest.mark.parametrize( "structured_outputs, match", [ (StructuredOutputsParams(json_object=False), "json_object must be True"), (StructuredOutputsParams(json=""), "json cannot be an empty string"), ], ) def test_degenerate_structured_outputs_rejected(structured_outputs, match): """json_object=False and an empty json schema pass the `is not None` exclusivity check but resolve to no structured-output key, so they must be rejected at request validation (-> 400) instead of reaching and crashing the engine.""" params = SamplingParams(structured_outputs=structured_outputs) with pytest.raises(ValueError, match=match): params._validate_structured_outputs( _StubModelConfig(is_diffusion=False), StructuredOutputsConfig(), tokenizer=object(), )