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
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

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, unless you created the client with auto_resume_tracks=False. 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
An operation still in flight does not stay pending: close() settles it with AbortedError. A send_command() whose reply had not arrived yet raises it in the coroutine that awaits it.

send_command()

Sends a command to the model and waits for its correlated reply.
Signature
The SDK carries a payload over 256 KiB, up to 64 MiB, when the runtime accepts data-channel chunking. A runtime that does not accept it keeps the 256 KiB limit, and a larger payload raises MessageTooLargeError. 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. A FileRef nested inside a list or a dict in data works too, for a parameter that takes several files. The SDK sends each one as an upload reference. See File Uploads for details.

upload_file()

Uploads a file and returns a FileRef that can be passed into send_command().
Signature
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
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
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.

set_bitrate()

Bounds what the whole connection may allocate, in bits per second. Needs a connected client.
Signature
None leaves a bound at the WebRTC default. The SDK reapplies the bounds after a reconnect. This ceiling and Track.set_bitrate()’s apply together, so the lower of the two wins. The 2.5 Mbps default that caps a video encoder is the track-level one, so raise that as well.
Example
start_bps names the initial encoder target. It has no effect from here: this call needs a live connection, and the ramp that start_bps skips is over by then.

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
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(). A client created with auto_resume_tracks=False sees its recvonly tracks here until it resumes them.

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

get_stats()

A snapshot of the live connection: RTT, jitter, packet loss, bitrates, the transport ICE selected, and the WebRTC engine’s own per-stream counters.
Signature
Returns a ConnectionStats. Raises InvalidStateError unless the session is ready.
Example

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").