Skip to main content
Reactor is the base class for every model on the platform. It speaks raw JSON over the wire: open a session, send commands by name, and receive generic message events. Typed SDKs like HeliosModel and other model-specific packages extend Reactor:
Inheritance
The typed SDKs add named methods that mirror the model’s published commands (set_prompt(), send_image(), …). Under the hood they call send_command() on this base class. Same wire protocol, just typed. You can always drop down to Reactor directly to send any command as raw JSON; see the SDK Reference overview for when each path makes sense. For the list of commands and events a specific model accepts, see the Model API Reference.

Constructor

Signature
str
required
The name of the model to connect to. Required — the constructor raises TypeError without it.
str
Your Reactor API key. The SDK automatically exchanges this for a token during connect(). Use this or jwt, not both — jwt wins if both are given.
str
A token to authenticate with directly, skipping the API key exchange.
str
default:"https://api.reactor.inc"
The API URL. Ignored if local=True.
bool
default:"False"
If True, connects to a local runtime at http://localhost:8080 and relaxes TLS verification. No API key required.
Example
model_name and api_key may also be given positionally — Reactor("your-model-name", "rk_...") — matching the old py-sdk’s own constructor order exactly, so a call site ported from there needs no rewrite. api_url is keyword-only, so it can never be confused with either.
The Reactor class also supports async with for automatic cleanup:
Context manager
No audio device is ever opened. A sendonly audio track carries only the PCM you push into it with Track.push_frame() — nothing is captured from your microphone. A model’s audio arrives on its Track, via on_frame, for you to play through whatever you like — nothing is played through your speakers on your behalf.

Methods

connect()

Establishes a connection to the Reactor Platform, waits for GPU assignment, and opens a WebRTC connection to the model. If api_key was provided, fetches a token first.
Signature
str
Attach to an existing session instead of creating a new one — the session this reactor adopts does not get terminated on disconnect().
int
Adopt a WebRTC connection slot a backend already registered for this session, instead of registering a new one. The connection-level analogue of session_id — most callers building a single connection per session leave this unset. See Multiple connections per session.

disconnect()

Disconnects and ends the session on the server. Not recoverable — there is no parameter to keep the session alive instead. To disconnect and later resume the same session, call reconnect() directly rather than disconnect() followed by connect().
Signature
A no-op if not connected. Only actually ends the session when this client created it — adopting one via session_id leaves it running for its owner.

reconnect()

Reconnects using the same session — after a transient failure, or called from ready to deliberately cycle the connection. Tears down the live connection itself first if there is one, without ending the session server-side, so there is no need to call disconnect() beforehand (doing so would end the session this is about to reuse).
Signature
Raises InvalidStateError if there is no session to reconnect to — nothing has connected yet, or a previous disconnect() already ended it.
recvonly tracks resume automatically. sendonly tracks do not — a track published before the reconnect is not published after it, so publish again for anything you were sending:
Track.published is False until that happens, and push_frame() raises rather than sending into a slot with nothing behind it.

close()

Synchronously tears down the connection. Prefer disconnect() in async code; close() exists for cleanup paths (like __del__) that cannot await.
Signature

send_command()

Sends a command to the model and waits for its correlated reply.
Signature
str
required
The command name. Must match a command defined on the model.
dict
required
The command payload. Shape depends on the command.
Returns {"type": ..., "data": ...} — the model’s typed reply to this specific command. Returns None if the handler ran and acknowledged the command but returned no message, as an auto-generated set_<field> setter does.
Example
To fire a command without waiting on the reply, schedule the call instead of awaiting it directly: asyncio.create_task(reactor.send_command(...)) — keep a reference to the task so it isn’t garbage-collected before it completes.
You can also pass FileRef values from upload_file() as parameters. See File Uploads for details.

upload_file()

Uploads a file and returns a FileRef that can be passed into send_command().
Signature
BinaryIO | bytes | str | PathLike
required
The file to upload. Accepts a file path, raw bytes, or a file-like object opened in binary mode.
str
Custom filename. Inferred from the file path or file object when not given. Defaults to "upload" for raw bytes.
str
MIME type. Guessed from the filename when not given. Defaults to "application/octet-stream".
Example
Only callable once the connection status is "ready" — raises InvalidStateError otherwise, the same guard request_clip() and Track.pause() use.

publish_track()

Activates a named sendonly track slot, so frames pushed with Track.push_frame() start reaching the model.
Signature
str
required
Track name. Must match a sendonly track name the model declares.
Returns the slot as a Track, so frames can go straight into it:
Example
A failed publish_track() does not clean up the session by itself. If you call it outside a try/finally (or before entering the block that calls disconnect()), a failure here can leave the session running with nothing attached to it — the next connect() attempt then fails with ConflictError against the orphaned session. Wrap the whole connected lifetime, publish included, in one try/finally: await reactor.disconnect().

unpublish_track()

Deactivates a sendonly track. Synchronous, unlike the other track methods — it never touches the network, only a local status check and a fire-and-forget notification.
Signature
str
required
The name of the track to stop publishing.
A failure here is logged, not raised. Unpublish is commonly the last call in a finally block, and raising there would replace whatever exception was already propagating instead of adding to it. Check the logs (reactor_sdk at WARNING) if a track seems to have stayed published.

track()

The named track, as a Track — the only way to push frames into a track, receive its frames, or pause/resume it. Its publish()/push_frame()/on_frame()/ pause()/resume() refuse whatever the track’s direction doesn’t allow instead of failing silently.
Signature
str
required
The track name.
Raises ValueError for a name the session doesn’t declare, once it has declared any tracks — before that (early in connect(), before the model’s capabilities arrive) any name is accepted, so handlers can be registered ahead of time. The same object comes back every time for a given name, including across a reconnect.
Example
Push a frame, receive one, or pause/resume a track through this Track object. publish_track() / unpublish_track() also stay on Reactor directly — publish_track() hands back this same Track.
See the full Track reference for every method and property.

tracks

Every track the session declares, in declaration order, as a TrackList — a list[Track] with with_kind()/with_direction()/one() filters chained on top, for finding a track without hardcoding its name.
Signature
Empty until the model’s capabilities arrive, shortly after connect().
Example
Media is delivered per track: register on_frame() for decoded frames, or on_raw_frame() for the same bytes with no NumPy conversion — found by name via track() or by filtering here. on("frame", ...) / on("audio", ...) raise ValueError at registration, since a single handler fed every recvonly track of a kind at once couldn’t tell them apart.

paused_tracks

The names of the recvonly tracks currently paused.
Signature
Recvonly tracks are resumed automatically once connected, so this is empty on a healthy session until something is paused with Track.pause().

request_schema()

Requests the model’s command schema, as an OpenAPI document — the same schema published on the Model API Reference pages, fetched at runtime.
Signature

request_clip()

Requests a clip covering the last duration_seconds of the session.
Signature
Returns a Clip. See Recordings for the full flow (the clip streams as HLS segments; this call returns the manifest, not the video itself).

request_recording()

Requests a clip covering the entire session up to now.
Signature

download_clip()

request_clip() and download_clip() in one call — for when the file is the only thing you want.
Signature
Given path, streams straight to it and returns None. Without one, returns the assembled bytes instead. See download_clip() for the full contract — same function, request_clip() called for you first.
Example
Reach for request_clip() directly instead if you also want the Clip’s session_id, its start_marker / end_marker, or predicted_ready_at_ms — or want to decide whether to download it at all based on what it says.

download_recording()

request_recording() and download_clip() in one call.
Signature
Example
Pass path: a full-session recording has no upper bound on length, and only the streamed-to-disk form (returns None) avoids holding the whole thing in memory. Omitting path returns the assembled bytes, which does mean holding the whole recording in memory to do it.

on()

Registers a handler for an event name.
Signature
See Events below for the full list of event names and their payloads.
"frame" and "audio" are not among them — media is delivered per track, not client-wide. Registering either raises ValueError at registration time, naming the Track method to use instead (on_frame() / on_raw_frame()).

off()

Removes a handler previously registered with on().
Signature

status / get_status()

The current connection status. get_status() is an older method form of the same thing — both exist, use whichever reads better.
Signature
Returns ReactorStatus.DISCONNECTED, CONNECTING, WAITING, or READY. ReactorStatus is a str subclass, so it compares equal to the plain string too (reactor.status == "ready").

session_id / get_session_id()

The current session ID, or None if not connected. get_session_id() is the older method form.
Signature

Events

on()/off() take the event name as a plain str — there is no separate ReactorEvent type to import.
Media is delivered per track. See Track.on_frame() / Track.on_raw_frame().
Python events use snake_case (e.g., "status_changed") while the JavaScript SDK uses camelCase (e.g., "statusChanged").