Promote the refine-override field accessors to module-level frozenset
constants (``REFINE_PRESET_OVERRIDE_FIELDS``,
``REFINE_STAGE_OVERRIDE_FIELDS``, ``REFINE_FLAT_KEYS``) so callers
reference a single source of truth instead of recomputing on each
call. Drop the redundant ``dict(deepcopy(value))`` double-copy on the
``torch_compile_kwargs`` legacy path, compress the
``_compile_config_to_torch_kwargs`` docstring, and remove a handful of
comments that just restated the code or named a future PR. Narrow the
schema-parity ``walk_packages`` traversal to
``configs/pipelines/*`` and ``basic/<family>/pipeline_configs`` so the
test no longer imports every heavy model module under ``basic/``.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Post-review cleanup (no behavior change):
Correctness:
* compat.py refine reverse-flatten now iterates
_LTX2_REFINE_FLAT_KEYS, which unions the typed
LTX2RefinePresetOverride and LTX2RefineStageOverride field sets.
The previous hardcoded 4-tuple missed image_crf and
video_position_offset_sec, so any init-time
preset_overrides.refine.image_crf would silently drop on reverse.
New regression test TestRefineFlattenCoversAllTypedFields pins the
invariant.
Simplification:
* refine_preset_override_to_dict and refine_stage_override_to_dict
were byte-identical; collapse to a single refine_override_to_dict.
* Trim narrative / PR-migration prose from docstrings and re-export
shims: stage_overrides.py module + field docstrings, schema.py
CompileConfig + PipelineSelection.vae_tiling, presets.py
LTX2_TWO_STAGE header, configs/pipelines/__init__.py and
pipelines/stages/__init__.py and ltx2/stages/__init__.py.
Move the LTX-2 family's PipelineConfig and the four LTX-2-specific
stage modules into fastvideo/pipelines/basic/ltx2/ so each model family
directory is self-contained (pipeline implementation + presets +
stage_overrides + pipeline_configs + stages in one place). See the
"Pipeline Package Structure" section in PR plan.md and the per-model
colocation plan in apirefactor.md Phase 8.
File moves (git mv preserves history):
fastvideo/configs/pipelines/ltx2.py
-> fastvideo/pipelines/basic/ltx2/pipeline_configs.py
fastvideo/pipelines/stages/ltx2_audio_decoding.py
-> fastvideo/pipelines/basic/ltx2/stages/ltx2_audio_decoding.py
fastvideo/pipelines/stages/ltx2_denoising.py
-> fastvideo/pipelines/basic/ltx2/stages/ltx2_denoising.py
fastvideo/pipelines/stages/ltx2_latent_preparation.py
-> fastvideo/pipelines/basic/ltx2/stages/ltx2_latent_preparation.py
fastvideo/pipelines/stages/ltx2_text_encoding.py
-> fastvideo/pipelines/basic/ltx2/stages/ltx2_text_encoding.py
Import/export updates:
- fastvideo/registry.py and tests/local_tests/test_ltx2_registry.py
now import LTX2T2VConfig from the new colocated path directly.
- fastvideo/configs/pipelines/__init__.py keeps the legacy
`fastvideo.configs.pipelines.LTX2T2VConfig` export by re-exporting
from the new location — external users of the old path keep working.
- fastvideo/pipelines/stages/__init__.py does the same for the four
LTX-2 stage classes, re-exporting from the new
pipelines/basic/ltx2/stages/ subpackage.
- new fastvideo/pipelines/basic/ltx2/stages/__init__.py is the
canonical home for the stage exports.
Parity-inventory walker (fastvideo/tests/api/test_schema_parity_inventory.py):
_get_extra_dataclass_fields now accepts a tuple of package roots and
descends recursively via pkgutil.walk_packages, so it discovers
PipelineConfig subclasses that have moved out of
fastvideo.configs.pipelines into fastvideo.pipelines.basic.<family>.
The pipeline_config_extensions classification test now walks both
roots so the LTX-2 fields (vocoder_config, audio_decoder_config,
vocoder_precision, audio_decoder_precision) stay accounted for.
Nothing else changes: no behavior change; no test changes beyond the
walker; all 210 API+entrypoints tests still pass.
Add typed public dataclasses that describe the LTX-2 refine override
surfaces, and bind them to the ltx2_two_stage preset's stage schema so
the validation-layer field set stays in lockstep with the dataclass:
* LTX2RefinePresetOverride (init-time, for preset_overrides.refine):
- enabled: bool | None — toggle the refine stage topology
- add_noise: bool | None — controls LTX2UpsampleStage noise mixing
* LTX2RefineStageOverride (per-request, for stage_overrides.refine):
- num_inference_steps: int | None — stage-2 denoise steps (2 or 3)
- guidance_scale: float | None — force_guidance_scale for stage-2
- image_crf: int | None — image-encoding CRF hint
- video_position_offset_sec: float | None — RoPE shift for audio
conditioning continuation
Asset wiring (upsampler weights, refine LoRA) stays on
ComponentConfig.upsampler_weights / .lora_path — no new typed home is
added here because those already exist.
The ltx2_two_stage refine stage schema's allowed_overrides now reads
from refine_stage_override_fields() so the dataclass is the single
source of truth. Serialisation helpers
(refine_{preset,stage}_override_to_dict) drop None entries so only
user-set fields flow through the preset/stage override dicts.
The runtime still reads the refine knobs off FastVideoArgs at
pipeline-construction time; wiring these typed objects through compat
+ runtime is the next slice. This commit ships only the public
typed surface and the preset/dataclass invariant.
12 new tests in fastvideo/tests/api/test_ltx2_stage_overrides.py cover
default None construction, explicit construction, to_dict() dropping
None, fields() accessor, and an invariant test proving the preset's
refine stage allowed_overrides exactly matches the dataclass fields.
Land the ltx2_two_stage inference preset (PR 6 commit 1/5) that exposes
the public LTX-2 two-stage distilled flow: half-resolution denoise
followed by 2x spatial upsample + stage-2 refine denoise (3 steps with
the official distilled sigma schedule, or 2 steps with the reduced
variant).
Schema:
- new _REFINE_STAGE PresetStageSpec with kind="refinement" and
allowed per-request overrides {num_inference_steps, guidance_scale,
image_crf, video_position_offset_sec}
- new LTX2_TWO_STAGE preset with stage_schemas=(denoise, refine) and
stage_defaults.refine={num_inference_steps: 2, guidance_scale: 1.0}
matching the load_kwargs the internal ltx2-streaming gpu_pool uses
- LTX2_TWO_STAGE registered via ALL_PRESETS -> _register_presets()
Init-time refine wiring (enabled, add_noise, upsampler/LoRA/transformer
paths) flows through generator.pipeline.preset_overrides.refine.* and
generator.pipeline.components.{upsampler_weights, lora_path} in a
follow-up commit — the refine stage's internal implementation
(fastvideo/pipelines/stages/ltx2_refine.py in FastVideo-internal) already
treats those as FastVideoArgs fields; this commit only ships the public
preset surface.
5 new tests under fastvideo/tests/api/test_presets.py::TestLtx2Presets:
registration count (3 presets now), two-stage topology, stage defaults,
valid per-request refine override keys, and unknown-override rejection.