diff --git a/docs/cookbook/diffusion/MiniMax/MiniMax-H3.mdx b/docs/cookbook/diffusion/MiniMax/MiniMax-H3.mdx
index af5e03200..96e7fe8c3 100644
--- a/docs/cookbook/diffusion/MiniMax/MiniMax-H3.mdx
+++ b/docs/cookbook/diffusion/MiniMax/MiniMax-H3.mdx
@@ -410,12 +410,19 @@ for variant in 0 1; do
done
```
-### Choose a quality profile
+### Choose the quality level
-`quality` is a request-scoped sampling parameter. One resident server can
-switch between all four profiles; an approximate request mounts its audited
-Cache-DiT policy at the batch boundary, and a later `lossless` request removes
-the hooks before denoising.
+`quality` is a request-scoped sampling parameter with two validated levels:
+
+- `"lossless"` (default): the exact reference path. Output is bit-exact
+ against the reference implementation and the CI ground truth.
+- `"high"`: the audited accelerated path. Quality is guaranteed (the audited
+ Cache-DiT configuration measures SSIM 0.931 / PSNR 28.16 dB against
+ `lossless`), but output is no longer bit-identical to the reference.
+
+One resident server serves both levels; a `quality: "high"` request mounts
+its audited Cache-DiT policy at the batch boundary, and a later
+`quality: "lossless"` request removes the hooks before denoising.
Start the validated server once:
@@ -434,13 +441,14 @@ sglang serve \
--port 30010
```
-Then choose a request tag:
+Then choose a request level:
-
+
-Native denoising with no feature-cache approximation. This is the default.
+Native denoising with no feature-cache approximation. This is the default;
+omitting the field is equivalent.
```json Request field
{
@@ -452,8 +460,8 @@ Native denoising with no feature-cache approximation. This is the default.
-The least aggressive approximate profile. Use it when output should stay
-closest to the same-seed lossless trajectory.
+The audited accelerated path. Use it when you can trade bit-exactness for
+latency while keeping output closest to the same-seed lossless trajectory.
```json Request field
{
@@ -463,32 +471,6 @@ closest to the same-seed lossless trajectory.
-
-
-The balanced profile: substantially lower latency with a larger change from
-the same-seed lossless output.
-
-```json Request field
-{
- "quality": "medium"
-}
-```
-
-
-
-
-
-The fastest validated profile and the largest visual deviation. Use it for
-latency-sensitive previews and high-throughput generation.
-
-```json Request field
-{
- "quality": "low"
-}
-```
-
-
-
The measured trade-off is:
@@ -497,8 +479,6 @@ The measured trade-off is:
| --- | ---: | ---: | ---: | ---: | --- |
| `lossless` | 75.10 s | 1.00× | 1.000 | exact | Native reference path |
| `high` | 53.70 s | 1.40× | 0.931 | 28.16 dB | Smallest same-seed visual change |
-| `medium` | 30.23 s | 2.48× | 0.818 | 20.40 dB | Balanced latency and visual deviation |
-| `low` | 25.81 s | 2.91× | 0.794 | 19.25 dB | Largest deviation; fastest preview path |
These numbers use 1344×768, 124-frame, 24 fps T2VA with 50 inference steps,
video flow shift 12, audio flow shift 3, and three fixed prompt/seed pairs on
@@ -506,26 +486,26 @@ video flow shift 12, audio flow shift 3, and three fixed prompt/seed pairs on
and a moving close-up portrait. `inference_time_s` is averaged across the three
prompts; the quiet-scene point is itself the mean of two repeats.
-SSIM and PSNR compare decoded, frame-aligned output with the `lossless` result
-for the same prompt and seed. They measure trajectory deviation, not absolute
-perceptual quality: an approximate profile can produce a different but still
-plausible realization. The profiles also change the joint audio-video denoise
+SSIM and PSNR compare decoded, frame-aligned output with the `lossless`
+result for the same prompt and seed. They measure trajectory deviation, not
+absolute perceptual quality: the `high` path can produce a different but
+still plausible realization. It also changes the joint audio-video denoise
trajectory, while these two metrics cover video only.
-Approximate profiles currently accept only the exact workload and 4×H200
+`quality: "high"` currently accepts only the exact workload and 4×H200
deployment above; other hardware, task modes, request shapes, step counts, or
-flow shifts fail before denoising. Offline generation uses the same profile
-name, for example `sglang generate --quality medium`.
+flow shifts fail before denoising. Offline generation uses the same level
+name, for example `sglang generate --quality high`.
-`quality` selects a model sampling profile and can change generated content.
+`quality` selects a model sampling level and can change generated content.
`output_quality` controls only output-file compression; it is a separate field.
-For manually tuned Cache-DiT experiments outside that validated profile, omit
+For manually tuned Cache-DiT experiments outside that validated path, omit
the request `quality` field and set the process-wide environment controls
-directly. An explicit `quality: lossless` request overrides those controls and
-restores native denoising:
+directly. An explicit `quality: "lossless"` request overrides those controls
+and restores native denoising:
```bash Command
SGLANG_CACHE_DIT_ENABLED=true \
@@ -548,8 +528,8 @@ Cache-DiT skips selected block computation and is approximate. It cannot be
combined with FSDP inference or DiT layerwise offload. Breakable CUDA graph
execution takes precedence and leaves Cache-DiT disabled. Tune the cache
thresholds only after comparing both video and audio quality on the target
-task profile. A real B200 request has completed, but the named profiles above
-remain fail-closed to the audited 4×H200 workload.
+task profile. A real B200 request has completed, but the `quality: "high"`
+path above remains fail-closed to the audited 4×H200 workload.
## 6. Runtime feature recipes
@@ -646,7 +626,7 @@ real H3 validation runs.
- MiniMax-H3 produces the canonical 24 fps output; request duration is expressed through `target.duration_seconds`.
- `target.duration_seconds` must be between 4 and 15 seconds, inclusive. The command picker defaults to the verified 5-second profile.
-- Use a 768-pixel short edge for the released quality profile. The aligned output dimensions are derived from `target.aspect_ratio`.
+- Use a 768-pixel short edge for the released quality recipe. The aligned output dimensions are derived from `target.aspect_ratio`.
- `flow_shift` controls video diffusion and `audio_flow_shift` controls audio diffusion.
- V2V uses `task: "ref2va"` with a `video` or `video_audio` reference; it is served by the `Ref2VA` partition and is not a separate public task value.
- `conditions[].start_time_seconds` selects a non-negative offset for a video reference. Its visual and audio streams are always sought together.
diff --git a/docs/docs/sglang-diffusion/api/cli.mdx b/docs/docs/sglang-diffusion/api/cli.mdx
index 6c0789947..0cb31ad31 100644
--- a/docs/docs/sglang-diffusion/api/cli.mdx
+++ b/docs/docs/sglang-diffusion/api/cli.mdx
@@ -105,7 +105,7 @@ Use `sglang generate --help` and `sglang serve --help` for the full argument lis
- `--image-path {PATH} [{PATH} ...]`: input image(s) for image-to-video or image-to-image generation
- `--num-inference-steps {STEPS}` and `--seed {SEED}`
- `--num-outputs-per-prompt {N}` / `--num-outputs {N}`: generate multiple outputs for each prompt. A scalar seed expands as `seed + output_index`.
-- `--quality {PROFILE}`: select a model-owned request quality/performance profile. Supported names and deployment constraints are model-specific.
+- `--quality {lossless,high}`: request-level quality. `lossless` (default) keeps the exact reference path, bit-exact against the reference implementation; `high` opts into the model-owned validated accelerated path, whose quality stays guaranteed but is not bit-exact. Support and validated deployment constraints are model-specific.
- `--height {HEIGHT}`, `--width {WIDTH}`, `--num-frames {N}`, `--fps {FPS}`
- `--output-path {PATH}`, `--output-file-name {NAME}`, `--save-output`, `--return-frames`
diff --git a/python/sglang/multimodal_gen/configs/pipeline_configs/minimax_h3.py b/python/sglang/multimodal_gen/configs/pipeline_configs/minimax_h3.py
index b42b70ea1..d3e6e4d03 100644
--- a/python/sglang/multimodal_gen/configs/pipeline_configs/minimax_h3.py
+++ b/python/sglang/multimodal_gen/configs/pipeline_configs/minimax_h3.py
@@ -84,7 +84,8 @@ class MiniMaxH3PipelineConfig(PipelineConfig):
return getattr(value, "value", value)
def validate_quality_deployment(self, server_args) -> None:
- """Fail closed unless the resident server matches the measured profile."""
+ """Fail closed unless the resident server matches the deployment
+ audited for quality="high"."""
attention_backend = self._server_arg_value(server_args.attention_backend)
attention_backend = (
@@ -161,7 +162,7 @@ class MiniMaxH3PipelineConfig(PipelineConfig):
}
if mismatches:
raise ValueError(
- "MiniMax-H3 approximate quality profiles are validated only for "
+ 'MiniMax-H3 quality="high" is validated only for '
f"the strict 4xH200 fl2va deployment; mismatches: {mismatches}"
)
diff --git a/python/sglang/multimodal_gen/configs/sample/sampling_params.py b/python/sglang/multimodal_gen/configs/sample/sampling_params.py
index c771c3ce8..c5636c507 100644
--- a/python/sglang/multimodal_gen/configs/sample/sampling_params.py
+++ b/python/sglang/multimodal_gen/configs/sample/sampling_params.py
@@ -51,6 +51,12 @@ def generate_request_id() -> str:
return str(uuid.uuid4())
+# Validated request-level quality levels. "lossless" is the exact reference
+# path (bit-exact against the CI golden outputs); "high" opts into validated
+# accelerated paths whose quality is guaranteed but not bit-exact.
+QUALITY_LEVELS: tuple[str, ...] = ("lossless", "high")
+
+
def _sanitize_filename(name: str, replacement: str = "_", max_length: int = 150) -> str:
"""Create a filesystem- and ffmpeg-friendly filename.
@@ -123,9 +129,20 @@ class SamplingParams:
)
output_quality: str | None = "default"
output_compression: int | None = None
- # Model-owned, request-scoped approximate acceleration profile. Models
- # that support it must validate the deployment and workload explicitly.
- # It intentionally participates in the dynamic-batch signature.
+ # Model-owned, request-scoped quality level.
+ #
+ # - "lossless" (default): the exact reference path. Output is expected to
+ # be bit-identical to the HF reference implementation and to pass the
+ # CI golden/ground-truth comparisons.
+ # - "high": opt into validated accelerated paths. Quality stays
+ # guaranteed (the intent is to back every such path with mathematical
+ # acceptance thresholds, e.g. PSNR > 25 against the reference), but
+ # the output is no longer bit-exact versus the HF reference or the CI
+ # ground truth.
+ #
+ # Models that support "high" must validate the deployment and workload
+ # explicitly. It intentionally participates in the dynamic-batch
+ # signature.
quality: str = "lossless"
# Frame interpolation
@@ -408,9 +425,10 @@ class SamplingParams:
f"prompt_path must be a txt file, got {self.prompt_path!r}"
)
- if not isinstance(self.quality, str) or not self.quality.strip():
+ if self.quality not in QUALITY_LEVELS:
raise ValueError(
- f"quality must be a non-empty string, got {self.quality!r}"
+ f"quality must be one of {list(QUALITY_LEVELS)}, "
+ f"got {self.quality!r}"
)
# These are always required to be sane regardless of pipeline.
@@ -932,9 +950,14 @@ class SamplingParams:
add_argument(
"--quality",
type=str,
+ choices=list(QUALITY_LEVELS),
help=(
- "Select a model-owned quality/performance profile. "
- "Support and validated deployment constraints are model-specific."
+ "Request-level quality: 'lossless' (default) keeps the exact "
+ "reference path, bit-exact against the reference "
+ "implementation; 'high' opts into the model-owned validated "
+ "accelerated path, whose quality stays guaranteed but is not "
+ "bit-exact. Support and validated deployment constraints are "
+ "model-specific."
),
)
add_argument(
diff --git a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/constants.py b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/constants.py
index 1f59adf35..61b79ed4a 100644
--- a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/constants.py
+++ b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/constants.py
@@ -27,11 +27,10 @@ MINIMAX_H3_MAX_DURATION_SECONDS = 15.0
# The distilled checkpoint has exactly one positive denoise branch.
MINIMAX_H3_DEFAULT_BRANCHES: tuple = ({"name": "cond_1"},)
-# Audited 4xH200 T2VA profiles. The tuple is
+# Audited 4xH200 T2VA Cache-DiT parameters for quality="high":
# (warmup steps, residual-difference threshold, max consecutive cached steps).
-MINIMAX_H3_QUALITY_PROFILES: dict[str, tuple[int, float, int] | None] = {
- "lossless": None,
- "high": (4, 0.04, 1),
- "medium": (4, 0.12, 3),
- "low": (4, 0.24, 3),
-}
+# Measured SSIM 0.931 / PSNR 28.16 dB against quality="lossless" on the
+# validated workload. quality="lossless" (the default) uses no Cache-DiT
+# configuration at all. Process-wide SGLANG_CACHE_DIT_* environment controls
+# remain available for manual experiments and are independent of this field.
+MINIMAX_H3_HIGH_QUALITY_CACHE_DIT_CONFIG: tuple[int, float, int] = (4, 0.04, 1)
diff --git a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/release_metadata.py b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/release_metadata.py
index 14e375a3d..475de96aa 100644
--- a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/release_metadata.py
+++ b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/release_metadata.py
@@ -7,11 +7,9 @@ import math
from dataclasses import dataclass
from typing import Any, Mapping
+from sglang.multimodal_gen.configs.sample.sampling_params import QUALITY_LEVELS
from sglang.multimodal_gen.runtime.pipelines_core.schedule_batch import Req
from sglang.multimodal_gen.runtime.pipelines_core.stages.base import PipelineStage
-from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.constants import (
- MINIMAX_H3_QUALITY_PROFILES,
-)
from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.resolved_plan import (
minimax_h3_plan_from_batch,
)
@@ -150,25 +148,23 @@ class MiniMaxH3PartitionAdmissionStage(PipelineStage):
raise ValueError("MiniMax H3 request task must be a non-empty string")
self.metadata.canonical_task(task)
quality = getattr(batch.sampling_params, "quality", "lossless")
- if quality not in MINIMAX_H3_QUALITY_PROFILES:
+ if quality not in QUALITY_LEVELS:
raise ValueError(
- f"unsupported MiniMax-H3 quality profile {quality!r}; supported: "
- f"{list(MINIMAX_H3_QUALITY_PROFILES)}"
+ f"quality must be one of {list(QUALITY_LEVELS)}, got {quality!r}"
)
- approximate = quality != "lossless"
+ high_quality = quality == "high"
attention_backend = str(server_args.attention_backend or "").strip().lower()
if attention_backend == "sage_attn" and not batch.is_warmup:
raise ValueError(
"MiniMax-H3 does not support SageAttention: the current packed "
"varlen path does not preserve model output"
)
- if approximate and not batch.is_warmup:
+ if high_quality and not batch.is_warmup:
server_args.pipeline_config.validate_quality_deployment(server_args)
plan = minimax_h3_plan_from_batch(batch)
if plan is None:
raise ValueError(
- "MiniMax-H3 approximate quality profiles require a resolved "
- "request plan"
+ 'MiniMax-H3 quality="high" requires a resolved request plan'
)
shape = plan.shape
actual = {
@@ -212,7 +208,7 @@ class MiniMaxH3PartitionAdmissionStage(PipelineStage):
)
if not exact or not shifts:
raise ValueError(
- "MiniMax-H3 approximate quality profiles are validated only for "
+ 'MiniMax-H3 quality="high" is validated only for '
f"{_MINIMAX_H3_QUALITY_WORKLOAD}; got {actual}"
)
return batch
diff --git a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/denoising.py b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/denoising.py
index 802388c6f..568e82a0c 100644
--- a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/denoising.py
+++ b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/denoising.py
@@ -24,7 +24,7 @@ from sglang.multimodal_gen.runtime.pipelines_core.stages.denoising import (
DenoisingStage,
)
from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.constants import (
- MINIMAX_H3_QUALITY_PROFILES,
+ MINIMAX_H3_HIGH_QUALITY_CACHE_DIT_CONFIG,
)
from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.task_profiles import (
MINIMAX_H3_FL2VA_KEYFRAME_SIGNATURES,
@@ -387,7 +387,7 @@ class MiniMaxH3DenoisingStage(DenoisingStage):
scheduler=None,
pipeline=pipeline,
)
- self._minimax_h3_quality_profile = "lossless"
+ self._minimax_h3_quality = "lossless"
self._minimax_h3_cache_mode: str | None = None
def _owns_compile_warmup_lifecycle(self) -> bool:
@@ -395,7 +395,7 @@ class MiniMaxH3DenoisingStage(DenoisingStage):
def _cache_dit_requested(self) -> bool:
return (
- getattr(self, "_minimax_h3_quality_profile", "lossless") != "lossless"
+ getattr(self, "_minimax_h3_quality", "lossless") == "high"
or super()._cache_dit_requested()
)
@@ -403,19 +403,15 @@ class MiniMaxH3DenoisingStage(DenoisingStage):
self, num_inference_steps: int | tuple[int, int], batch: Req
) -> None:
quality = getattr(batch.sampling_params, "quality", "lossless")
- if quality not in MINIMAX_H3_QUALITY_PROFILES:
- raise ValueError(f"unsupported MiniMax-H3 quality profile {quality!r}")
explicit_fields = getattr(batch.sampling_params, "_explicit_fields", ())
generic_requested = (
super()._cache_dit_requested() and "quality" not in explicit_fields
)
desired_mode = (
- quality
- if quality != "lossless"
- else ("generic" if generic_requested else None)
+ "high" if quality == "high" else ("generic" if generic_requested else None)
)
current_mode = getattr(self, "_minimax_h3_cache_mode", None)
- self._minimax_h3_quality_profile = quality
+ self._minimax_h3_quality = quality
# H3 is monolithic-only, and the scheduler executes one worker batch at
# a time. Combined with `quality` in the dynamic-batch signature, this
@@ -435,7 +431,7 @@ class MiniMaxH3DenoisingStage(DenoisingStage):
def _cache_dit_scm_masks(
self, primary_num_steps: int, secondary_num_steps: int | None = None
) -> tuple[str, str, list[int] | None, list[int] | None]:
- if getattr(self, "_minimax_h3_quality_profile", "lossless") != "lossless":
+ if getattr(self, "_minimax_h3_quality", "lossless") == "high":
return "none", "dynamic", None, None
return super()._cache_dit_scm_masks(primary_num_steps, secondary_num_steps)
@@ -447,16 +443,14 @@ class MiniMaxH3DenoisingStage(DenoisingStage):
*,
secondary: bool = False,
) -> CacheDitConfig:
- quality = getattr(self, "_minimax_h3_quality_profile", "lossless")
- profile = MINIMAX_H3_QUALITY_PROFILES[quality]
- if profile is None or secondary:
+ if secondary or getattr(self, "_minimax_h3_quality", "lossless") != "high":
return super()._build_cache_dit_config(
num_inference_steps,
steps_computation_mask,
scm_policy,
secondary=secondary,
)
- warmup, threshold, max_cached = profile
+ warmup, threshold, max_cached = MINIMAX_H3_HIGH_QUALITY_CACHE_DIT_CONFIG
return CacheDitConfig(
enabled=True,
Fn_compute_blocks=1,
diff --git a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/video_adapter.py b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/video_adapter.py
index 7ab71a609..a51c69099 100644
--- a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/video_adapter.py
+++ b/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/video_adapter.py
@@ -11,6 +11,7 @@ from typing import TYPE_CHECKING, Any
from sglang.multimodal_gen.configs.pipeline_configs.minimax_h3 import (
MiniMaxH3PipelineConfig,
)
+from sglang.multimodal_gen.configs.sample.sampling_params import QUALITY_LEVELS
from sglang.multimodal_gen.runtime.entrypoints.openai.protocol import (
VideoGenerationsRequest,
)
@@ -104,12 +105,14 @@ class MiniMaxH3VideoModelAdapter:
request: VideoGenerationsRequest,
name: str,
) -> str | None:
- value = _parse_extra_value(_extra_value(request, name))
+ value = _extra_value(request, name)
if value is None:
return None
- if not isinstance(value, str) or not value.strip():
- raise ValueError(f"{name} must be a non-empty string")
- return value.strip().lower()
+ if value not in QUALITY_LEVELS:
+ raise ValueError(
+ f"{name} must be one of {list(QUALITY_LEVELS)}, got {value!r}"
+ )
+ return value
@staticmethod
def _reject_retired_cfg_fields(kwargs: dict[str, Any]) -> None:
diff --git a/python/sglang/multimodal_gen/test/unit/test_minimax_h3_admission.py b/python/sglang/multimodal_gen/test/unit/test_minimax_h3_admission.py
index 229f109be..19b8ee681 100644
--- a/python/sglang/multimodal_gen/test/unit/test_minimax_h3_admission.py
+++ b/python/sglang/multimodal_gen/test/unit/test_minimax_h3_admission.py
@@ -208,6 +208,21 @@ def test_video_adapter_lowers_only_native_fields_and_rejects_cfg():
)
+@pytest.mark.parametrize("bad_quality", ["ultra", "draft", "", 1])
+def test_video_adapter_rejects_invalid_quality(bad_quality):
+ request = VideoGenerationsRequest(
+ prompt="contract",
+ task="t2va",
+ conditions=[],
+ target=TARGET,
+ quality=bad_quality,
+ )
+ with pytest.raises(ValueError, match="quality must be one of"):
+ MiniMaxH3SamplingParams.lower_video_request_kwargs(
+ request, {"prompt": request.prompt, "seed": request.seed}
+ )
+
+
class _HopperCapability:
def to_int(self) -> int:
return 90
@@ -289,7 +304,7 @@ def test_quality_admission_fails_closed_outside_validated_request():
with pytest.raises(ValueError, match="does not support SageAttention"):
stage.forward(batch, server_args)
- batch.sampling_params.quality = "unsupported"
+ batch.sampling_params.quality = "ultra"
server_args.attention_backend = None
- with pytest.raises(ValueError, match="unsupported MiniMax-H3 quality profile"):
+ with pytest.raises(ValueError, match="quality must be one of"):
stage.forward(batch, server_args)
diff --git a/python/sglang/multimodal_gen/test/unit/test_sampling_params.py b/python/sglang/multimodal_gen/test/unit/test_sampling_params.py
index 7beca3bd2..cfdf58f2a 100644
--- a/python/sglang/multimodal_gen/test/unit/test_sampling_params.py
+++ b/python/sglang/multimodal_gen/test/unit/test_sampling_params.py
@@ -41,12 +41,17 @@ class TestSamplingParamsValidate(unittest.TestCase):
with self.assertRaisesRegex(ValueError, r"num_outputs_per_prompt"):
SamplingParams(num_outputs_per_prompt=0)
- def test_quality_must_be_a_non_empty_profile_name(self):
+ def test_quality_defaults_to_lossless(self):
+ self.assertEqual(SamplingParams().quality, "lossless")
+
+ def test_quality_accepts_the_two_validated_levels(self):
+ self.assertEqual(SamplingParams(quality="lossless").quality, "lossless")
self.assertEqual(SamplingParams(quality="high").quality, "high")
- with self.assertRaisesRegex(ValueError, r"quality must be a non-empty string"):
- SamplingParams(quality="")
- with self.assertRaisesRegex(ValueError, r"quality must be a non-empty string"):
- SamplingParams(quality=True) # type: ignore[arg-type]
+
+ def test_quality_rejects_invalid_values(self):
+ for bad in ("ultra", "draft", "fast", "", True, 1):
+ with self.assertRaisesRegex(ValueError, r"quality must be one of"):
+ SamplingParams(quality=bad) # type: ignore[arg-type]
def test_seed_accepts_int_or_non_empty_int_list(self):
self.assertEqual(SamplingParams(seed=7).seed, 7)
@@ -235,7 +240,7 @@ class TestSamplingParamsCliArgs(unittest.TestCase):
def test_quality_is_request_scoped_cli_arg(self):
self.assertNotIn("quality", self._parse_cli_kwargs([]))
self.assertEqual(
- self._parse_cli_kwargs(["--quality", "medium"])["quality"], "medium"
+ self._parse_cli_kwargs(["--quality", "high"])["quality"], "high"
)
def test_qwen_image_cli_path_preserves_model_defaults(self):