@event marks a method as a command handler, and a
ModelMessage subclass declares a message. The runtime turns those declarations into the model’s
schema, which is what typed client SDKs are generated from. The examples on this page come from
the runtime’s Waypoint example, a world model that starts from an uploaded image.
Defining a command
The state gives you oneset_<field> command per field, for values a client sets and the model
keeps reading. For anything else, write a handler with @event. The method’s parameters are the
data the client sends:
waypoint.py
set_image with an image parameter. The runtime validates the payload
against the signature before your method runs, and it runs between steps, so the state is never
changed while generate() is reading it. A handler can be async def or a plain def.
A command does not need parameters. This one restarts the world from the image the model already
has:
waypoint.py
Constraining a parameter
InputField on a parameter carries the same rules as on a state field, and the runtime checks them
before your handler runs:
invalid_command and your handler is not called. The
constraints also travel into the schema, so a client sees the accepted range before it sends
anything.
Replying to a command
A client that sends a command usually wants to know what happened. Return aModelMessage from
the handler and the runtime delivers it to that client as the reply to that exact command. A
client awaiting the call receives it as the result:
waypoint.py
None when there is nothing to say. Reply when the client should confirm what took effect:
a clamped value, a resolved default, the state after a change.
The return annotation has to be one ModelMessage subclass or None. A union such as
WaypointStatus | None is rejected when the class is declared, because the schema publishes one
reply shape per command.
Reporting a failure
When a command cannot be carried out, raiseCommandError with a code and a message. Both reach
the client as the reply to that command, so an awaiting caller gets an error instead of waiting
forever:
waypoint.py
internal_error, so
paths, queries, or credentials in the exception text never leave the container.
The runtime uses the same channel for its own refusals: invalid_command when a payload fails
validation, and unresolved_upload when a command references a file that cannot be fetched.
Sending messages
AModelMessage subclass declares a typed message. Send one with self.send() from anywhere in
your class, and every connected client receives it:
waypoint.py
{"type": "waypoint_status", "data": {...}}. The wire type is the
snake_case form of the class name. MessageField is optional; it attaches a description or a
default that shows up in the schema, and the class docstring documents the message itself. A
message with no fields is valid and is the right shape for a pure signal.
A message sent from process_output() goes on the wire before that step’s frames, so a client that
reads the status and then sees the frame gets them in that order.
Messages to one client
self.send() goes to everyone. To reach the client a handler or hook is running for, add a
client: ClientInfo parameter. The runtime fills it in, and client.send() delivers to that
client alone:
waypoint.py
File uploads
To receive a file with a command, annotate a parameter asUploadedFile. The runtime fetches the
upload and hands your handler the bytes:
UploadedFile carries name, mime_type, data (the raw bytes), and size. Check mime_type
before decoding, because a client can upload anything. A parameter can also be a
list[UploadedFile], and an upload nested inside a dict or a dataclass field resolves the same
way.
A client can also upload a file on its own, outside any command. Declare a @file_uploaded hook
to receive those:
uploaded_file, plus the optional client. Prefer putting
a file on the command it belongs to, so the schema tells the client what the file is for. Use
@file_uploaded for a drop zone or a client that uploads first and decides later.
Next
Sessions & Clients
Session and connection hooks, the client handle, and serving several clients.
Managing State
The state object and the commands it generates.