diff --git a/tests/inputs/test_diffusion_sampling_params.py b/tests/inputs/test_diffusion_sampling_params.py new file mode 100644 index 000000000..5daa1fd49 --- /dev/null +++ b/tests/inputs/test_diffusion_sampling_params.py @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: Apache-2.0 +"""Regression tests for diffusion sampling params coercion.""" + +from __future__ import annotations + +from typing import Any + +import pytest +from vllm.sampling_params import SamplingParams + +from vllm_omni.inputs.data import OmniDiffusionSamplingParams + +pytestmark = [pytest.mark.core_model, pytest.mark.cpu] + + +def _sampling_params(*, seed: int | None = None, extra_args: dict[str, Any] | None = None) -> SamplingParams: + return SamplingParams(max_tokens=1, seed=seed, extra_args=extra_args) + + +def test_from_params_returns_existing_omni_params() -> None: + params = OmniDiffusionSamplingParams(num_inference_steps=20) + + converted = OmniDiffusionSamplingParams.from_params(params) + + assert converted is params + + +def test_from_params_converts_sampling_params_seed_and_known_extra_args() -> None: + params = _sampling_params( + seed=1234, + extra_args={ + "num_inference_steps": 50, + "height": 1024, + "width": 768, + "guidance_scale": 7.5, + }, + ) + + converted = OmniDiffusionSamplingParams.from_params(params) + + assert converted.seed == 1234 + assert converted.num_inference_steps == 50 + assert converted.height == 1024 + assert converted.width == 768 + assert converted.guidance_scale == 7.5 + assert converted.extra_args == {} + + +def test_from_params_preserves_unknown_extra_args() -> None: + params = _sampling_params( + extra_args={ + "height": 512, + "pipeline_specific": "kept", + }, + ) + + converted = OmniDiffusionSamplingParams.from_params(params) + + assert converted.height == 512 + assert converted.extra_args == {"pipeline_specific": "kept"} + + +def test_from_params_rejects_unsupported_types() -> None: + with pytest.raises(TypeError, match="Diffusion stage requires OmniDiffusionSamplingParams"): + OmniDiffusionSamplingParams.from_params({"height": 512}) diff --git a/vllm_omni/engine/stage_pool.py b/vllm_omni/engine/stage_pool.py index 487134db1..820b28510 100644 --- a/vllm_omni/engine/stage_pool.py +++ b/vllm_omni/engine/stage_pool.py @@ -937,10 +937,9 @@ class StagePool: ) -> int: """Submit a stage-entry request into this pool.""" params = params_override if params_override is not None else req_state.sampling_params_list[self.stage_id] - # Convert plain vllm SamplingParams for single-stage diffusion models - # that receive sampling params from the user/caller directly. - if self.stage_type == "diffusion" and not isinstance(params, OmniDiffusionSamplingParams): - params = OmniDiffusionSamplingParams() + # Direct engine callers may provide plain vLLM SamplingParams. + if self.stage_type == "diffusion": + params = OmniDiffusionSamplingParams.from_params(params) submit_kwargs = dict(submit_kwargs or {}) if self.stage_type == "diffusion": if isinstance(request, list): @@ -1003,8 +1002,8 @@ class StagePool: ) -> int: """Submit a streaming update to an already admitted request.""" params = req_state.sampling_params_list[self.stage_id] - if self.stage_type == "diffusion" and not isinstance(params, OmniDiffusionSamplingParams): - params = OmniDiffusionSamplingParams() + if self.stage_type == "diffusion": + params = OmniDiffusionSamplingParams.from_params(params) replica_id = self.get_bound_replica_id(request_id) if replica_id is None or self.clients[replica_id] is None: replica_id = await self._pick_or_select(request_id) diff --git a/vllm_omni/inputs/data.py b/vllm_omni/inputs/data.py index 6626176b6..61d3d12a3 100644 --- a/vllm_omni/inputs/data.py +++ b/vllm_omni/inputs/data.py @@ -380,5 +380,30 @@ class OmniDiffusionSamplingParams: def clone(self) -> "OmniDiffusionSamplingParams": return copy.deepcopy(self) + @classmethod + def from_params(cls, params: Any) -> "OmniDiffusionSamplingParams": + """Normalize caller params for diffusion stages. + + Existing Omni params are returned unchanged. Plain vLLM SamplingParams + copy seed and matching extra_args fields; remaining extra_args stay nested. + Unsupported types raise TypeError. + """ + if isinstance(params, cls): + return params + if isinstance(params, SamplingParams): + extra = dict(getattr(params, "extra_args", None) or {}) + known = set(cls.__dataclass_fields__) + mapped = {k: extra.pop(k) for k in list(extra) if k in known} + if extra: + mapped["extra_args"] = extra + seed = getattr(params, "seed", None) + if seed is not None: + mapped.setdefault("seed", seed) + return cls(**mapped) + raise TypeError( + "Diffusion stage requires OmniDiffusionSamplingParams or vllm.SamplingParams, " + f"got {type(params).__name__!r}." + ) + OmniSamplingParams: TypeAlias = SamplingParams | OmniDiffusionSamplingParams