generate() over
and over, and each call is one step that produces the next piece of output: a frame, a chunk of
frames, a stretch of audio. Between steps the client’s inputs change: a new prompt, a key pressed,
a camera turned. The state is where those inputs live. A client sets a field from wherever it is,
the runtime stores the value, and the next step reads it. Your model never handles the message
itself.
One value over time. A client changes it between two steps, and every step after that reads the new value.
generate() call produces the next chunk of frames.
Declaring the state
The state is a class that extendsInputState, annotated on your model as state:. Each field
gets a type, a default, and optionally some bounds:
sana_wm.py
generate() receives, and it is also available as self.state anywhere else in the class.
What a field becomes
Every public field turns into a command namedset_<field>. The client sends the new value, the
runtime checks it against the field’s type and bounds, and if it passes, the field changes.
Clients set individual fields from outside. generate() reads the whole object on every step.
prompt: str
default:"a misty valley at sunrise"
The scene to generate. A new prompt starts a fresh rollout. Up to 500 characters.
move: str
default:"idle"
Camera movement, held until changed. One of
idle, forward, back, strafe_left,
strafe_right.yaw: int
default:"0"
Turn the camera: -1 left, 0 still, 1 right.
pitch: int
default:"0"
Tilt the camera: -1 down, 0 still, 1 up.
set_move with
forward on key down, set_move with idle on key up, and the camera keeps moving through every
chunk in between.
Validation
The constraints you write into a field are what the runtime checks before the value reaches your model. A value outside them is refused withinvalid_command, the field keeps its old value, and
your code is never called: a set_move with "jump" never gets through.
Bounds on numbers (ge, le), string lengths (min_length, max_length), a fixed set of
(choices), and a moderate mark for free text all live on the field declaration, alongside the
default and the description a client sees.
InputField()
Every argument the field declaration accepts, with what each one enforces.
Private fields
A field whose name starts with an underscore is yours alone. No command is generated for it, the client never sees it, and it resets with the rest of the state when a session ends. Use it for values the model needs to remember between steps but that a client should not set directly. SANA-WM starts every rollout from a first frame the client uploads. The upload arrives through a hand-written command, the handler decodes it and stores the result in a private field, andgenerate() reads it from there:
sana_wm.py
prompt: str
default:"a misty valley at sunrise"
Up to 500 characters.
move: str
default:"idle"
One of
idle, forward, back._first_frame and _first_frame_id do not appear. Keep private fields to plain data, such as
arrays, strings, and ids. GPU tensors belong on the model, not on the state.
Overriding a generated command
Sometimes setting a value should also do something else: reply to the client, cut the video, or remember that something changed. Write an@event handler with the same name as the generated
command and it takes over. The field stays a field; only what happens when the client sets it
changes.
A new prompt starts a fresh rollout, and the model needs to know that on its next step. The
override below writes the prompt as before, bumps a private counter so generate() can tell a
new prompt from a repeated one, and drops the frames still queued for playout so the client does
not receive the tail of the old scene:
sana_wm.py
set_prompt is still one command with one string. The
private field is how the handler and generate() talk to each other without the client seeing it.
You can also define entirely new commands that the client can call, for any action you want to
expose. Events & Messages shows how.
When the state resets
The runtime builds the state from the defaults when a session starts and drops it when the session ends. A client that disconnects and reconnects within the same session finds the values it left. A new session starts clean.Next
Events & Messages
Hand-written commands, replies, and messages from the model to the client.
Video & Audio Tracks
Receive the client’s camera and microphone as input tracks.