Files
hao-ai-lab-FastVideo/mini_fastvideo/request/requests.py
T
SolitaryThinker 270fae959d [feat] mini-fastvideo: model-native runtime per design_v3 (Wan2.1/LTX2 + 4 training methods)
A scoped, CPU-testable realization of design_v3.md — the architecture where the atomic unit
is a typed (recipe, runtime) ModelCard, the model owns loop semantics while the runtime owns
loop lifecycle, one resident instance runs many loops, and training records behavior on the
same loops it serves.

Implements:
- card/ loop/ runtime/ cache/ memory/ parallel/ parity/ extend/ program/ request/ training/
  spanning design_v3 §4-§13: ModelCard + validate(); driven loops (init/next/advance/finalize);
  step-interleaving Engine with reservation-before-admission + per-class caches keyed by CacheKey;
  the C0-C4 consistency ladder + the non-negotiable batch-of-N interleave parity gate.
- Inference: Wan2.1-1.3B (T2V), LTX2.3 (two-stage distilled, shared transformer), Wan-causal
  (chunk rollout + slab-KV streaming).
- Training (Wan2.1-1.3B), each driving the SAME loops the engine serves: finetune (flow-match),
  DMD2 (teacher/critic distribution matching), DiffusionNFT (likelihood-free C2, samples from the
  decay-blended old policy, group-relative advantages, shared-prompt cache reuse), self-forcing
  (causal chunk loop). The engine never imports training (the §10 dependency rule, grep-verified).

numpy-only core (no torch/GPU here); heavy Wan/LTX forwards are deterministic toy stand-ins with
lazy torch-adapter seams (ComponentSpec.load_id/factory) for a GPU box. 49 tests pass via pytest
and a zero-dependency runner; interleave parity verified (and a buggy module-global interceptor
provably breaks it). Omni-ready spine (ar_decode/chunk_step loop kinds, multi-loop instances,
LoopState.extension) for the phase-2 Cosmos3 + vllm-omni omni ports.

Run: python3 -m pytest mini_fastvideo/tests/ -q ; python3 -m mini_fastvideo.examples
2026-07-04 17:15:33 +00:00

98 lines
3.6 KiB
Python

"""Request + Session — the only currency crossing the product boundary (design_v3 §12).
"A typed ``Request`` carries ``task`` (declared, never inferred), ``inputs``
(ModalParts), AR ``sampling`` vs ``diffusion`` params, an ``OutputSpec``, and
per-node overrides." Products construct Requests; they never reach into the model.
"""
from __future__ import annotations
import itertools
from dataclasses import dataclass, field
from .cancel import CancelKind, CancelScope
from .modalpart import ImagePart, ModalPart, TextPart
from .params import DiffusionParams, OutputSpec, SamplingParams
from .streams import Stream
from .tasks import TaskType
_counter = itertools.count(1)
def new_request_id() -> str:
return f"req-{next(_counter)}"
@dataclass(frozen=True)
class Request:
request_id: str
task: TaskType
model_id: str # which ModelCard to run
inputs: tuple[ModalPart, ...] = ()
sampling: SamplingParams = field(default_factory=SamplingParams)
diffusion: DiffusionParams = field(default_factory=DiffusionParams)
outputs: OutputSpec = field(default_factory=OutputSpec)
node_params: dict[str, dict] = field(default_factory=dict) # per graph-node overrides
priority: int = 0
# --- convenience accessors (do not infer task from these; §12) ---
def prompt(self) -> str:
for p in self.inputs:
if isinstance(p, TextPart):
return p.text
return ""
def image(self):
for p in self.inputs:
if isinstance(p, ImagePart):
return p
return None
def node_override(self, node_id: str) -> dict:
return self.node_params.get(node_id, {})
def make_request(task: TaskType, model_id: str, prompt: str = "", *,
inputs: tuple[ModalPart, ...] | None = None,
sampling: SamplingParams | None = None,
diffusion: DiffusionParams | None = None,
outputs: OutputSpec | None = None,
node_params: dict[str, dict] | None = None,
priority: int = 0,
request_id: str | None = None) -> Request:
"""Ergonomic constructor used by the offline API and tests."""
parts: tuple[ModalPart, ...] = inputs if inputs is not None else ((TextPart(prompt),) if prompt else ())
return Request(
request_id=request_id or new_request_id(),
task=task, model_id=model_id, inputs=parts,
sampling=sampling or SamplingParams(),
diffusion=diffusion or DiffusionParams(),
outputs=outputs or OutputSpec(),
node_params=node_params or {},
priority=priority,
)
@dataclass
class Session:
"""A long-lived interactive context (design_v3 §12, §15e Dreamverse).
Holds prompt memory, media streams, a cancel scope, and a handle to
cross-request chunk-KV that persists for a game/scene session (self-forcing /
world-model rollout). Mutable by design.
"""
session_id: str
prompt_memory: list[str] = field(default_factory=list)
streams: dict[str, Stream] = field(default_factory=dict)
cancel_scope: CancelScope | None = None
kv_handle: object | None = None # persistent chunk-KV CacheHandle (see cache/)
def __post_init__(self):
if self.cancel_scope is None:
self.cancel_scope = CancelScope(kind=CancelKind.SESSION, target_id=self.session_id)
def push_text(self, text: str) -> None:
self.prompt_memory.append(text)
def stream(self, name: str) -> Stream:
return self.streams.setdefault(name, Stream(f"{self.session_id}:{name}"))