
reactor-sdk 1.0.0 (Python)
Breaking
send_command()now waits for its reply. Previously fire-and-forget — the call resolved as soon as the command was queued, and any reply from the model arrived later as a separatemessageevent. It now returns the model’s correlated reply directly:{"type": ..., "data": ...}, orNoneif the handler acknowledged the command without returning a message (an auto-generatedset_<field>setter, for instance). To fire a command without waiting on the reply, schedule the call instead of awaiting it directly —asyncio.create_task(reactor.send_command(...))— keeping a reference to the task so it isn’t garbage-collected before it completes.- Errors are now typed exceptions, and
ReactorErroris the one class for both. Every failure used to arrive as one bare exception carrying only a sentence, and separately,on_errorhanded you a same-shaped-but-different dataclass.ReactorErroris now both: the base of 16 concrete subclasses (UnauthorizedError,ConflictError,RateLimitedError, and more — see Error codes) thaton_errorand a raised call hand you identically, each with a stablecode,recoverable,status,operation,retry_after_ms, and (event-only)timestamp_ms. The oldcomponentfield (api/gpu) is gone — it split codes by platform tier, which wasn’t actionable and could report the same failure under two different codes.except ReactorErrorstill catches everything; code relying onerror.componentneeds updating. - Audio devices are synthetic-only. The constructor’s
adm_modeargument is gone; noReactorinstance ever opens a real microphone or speaker on its own. Asendonlyaudio track only ever carries PCM you push yourself withTrack.push_frame(), and a model’s audio must be played back explicitly viaTrack.on_frame()/on_raw_frame()— or withSpeaker/Microphone, below. reactor.on_frame(client-wide) is removed. It only ever worked for video, and a single handler fed everyrecvonlyvideo track couldn’t tell them apart. Register on theTrackinstead, found by name (reactor.track(name)) or by filteringreactor.tracks(reactor.tracks.with_direction("recvonly").with_kind("video").one()).- The client-wide
on("frame", ...)/on("audio", ...)events are removed too, for the same reason.on()raisesValueErrorat registration for either name, naming theTrackmethod to use instead —on_frame()for decoded frames,on_raw_frame()for the same bytes with no NumPy conversion. publish_track()/unpublish_track()are the only name-based track methods still public onReactor.push_video_frame(),push_audio_frame(),pause_track(), andresume_track()are now internal — reach the same operations through theTrackobject instead:track.push_frame(),track.pause(),track.resume().publish_track()already hands back that sameTrack.Track.push_frame()now raisesInvalidStateErroron an unpublishedsendonlytrack, rather than silently dropping the frame. Callpublish()first —Track.publishedsays whether that’s already happened.reconnect()resumesrecvonlytracks automatically, but does not restore asendonlytrack’s publish. Callpublish()again after reconnecting for anything you were sending before it.@reactor.on_trackhands over theTrackitself, not a bare(name, mid). TheTrackis already resolved —reactor.track(name)done for you — so a handler that wants to push frames or registeron_frameno longer has to look it up first;track.midstill carries the WebRTC media stream ID.unpublish_track()/Track.unpublish()returnNone, not anint. A failure is now logged (reactor_sdkatWARNING) rather than left for the caller to notice by checking a return value nobody checked — unpublish is commonly the last call in afinallyblock, so it still does not raise.Reactor()’s positional arguments aremodel_name,api_key—api_urlmoved to keyword-only. Matches the oldpy-sdk’s own constructor order exactly, soReactor(model, key)ported from there needs no rewrite to keyword arguments at all. Previouslyapi_url/model_namewere positional (in either order, sniffed by which one looked like a URL); any call relying on that specifically needs updating, but a plainReactor("your-model-name")is unaffected.upload_file()now requiresready. Previously allowed as soon as the coordinator created a session, before the WebRTC handshake finished — raisesInvalidStateErrornow if called earlier, the same guardrequest_clip()andTrack.pause()already used. See File Uploads.
New
reactor.tracksis now aTrackList. Still a plainlist[Track]for iterating and indexing, withwith_kind()/with_direction()filters that chain, and.one()for the common case of “the track I mean, and an error if that’s ambiguous.” SeeTrackList.- The
Trackobject.reactor.track(name)andreactor.tracksreturn aTrackscoped to one named slot, withpublish(),push_frame(),on_frame()/on_raw_frame(), andpause()/resume()that raise on a direction mismatch instead of a silent no-op. Track.published. Whether asendonlytrack is currently activated — readable state for something the session itself doesn’t track, cleared automatically whenever the connection leavesready.download_clip(). Fetches every segment aClip’splaylist_urlnames. Given apath, streams straight to it (returnsNone, never holds more than one segment in memory — the one to use forrequest_recording()); without one, returns the assembled bytes instead. Takes an optionalon_progresscallback either way. Closes a real gap left by the rewrite off the oldpy-sdk, which had this asdownload_clip_as_file().reactor.download_clip(seconds)/reactor.download_recording().request_clip()/request_recording()plus the download above, in one call, for when the file is all you want.request_clip()/request_recording()still return just theClipfor anyone who also wants itssession_id, markers, orpredicted_ready_at_ms.connect(connection_id=...). Adopts a WebRTC connection slot a backend already registered for a session, the connection-level analogue ofsession_idadoption — see Multiple connections per session. Also closes a gap left by the rewrite: the oldpy-sdkhad this, and the JavaScript SDK still does.reconnect()now works fromready, not only after a drop. It tears the live connection down itself first — without ending the session, unlikedisconnect()— so there was never a need to calldisconnect()immediately before it; that combination is also no longer required.disconnect()’s own behavior is unchanged — it has always ended the session server-side, with no recoverable option — a few places in these docs previously described it backwards, now corrected. See Sessions.Speaker/Microphone(reactor_sdk.audio_devices). Play arecvonlyaudio track through real speakers, or capture a real microphone into asendonlytrack — context managers wrapping asounddevicestream around aTrack:with Speaker(output_track), Microphone(mic_track): .... Not re-exported fromreactor_sdk— the only part of this SDK with a runtime dependency, sopip install "reactor-sdk[audio]"and import fromreactor_sdk.audio_devicesdirectly.Speakerpromotes whatexamples/pygame_apphad hand-rolled;Microphoneis new.fetch_jwt(api_key, api_url=...)’sapi_urlis optional now, defaulting to the same production coordinatorReactor()itself defaults to. Pass it explicitly only when minting a token against a different one.
helios · Rewind
New
- Rewind. Helios saves snapshots of the scene and returns to them on demand.
save_snapshotcaptures the world state,rewindrestores it, andlist_snapshotsreports what the buffer holds. The buffer keeps up to 50 snapshots per session and evicts the oldest once full; aresetempties it, and it is released when the session ends. Each snapshot records the one it descends from, so a save after a rewind branches off the restored snapshot while a save without one extends the branch in progress, andcurrent_snapshot_idon thestatemessage says which branch is live. Rewinding restores the scene but not the prompt, so send the prompt you want to continue with after the rewind. Available in@reactor-models/heliosassaveSnapshot,rewind, andlistSnapshots, with the matchinguseHeliosSnapshotSaved,useHeliosRewindComplete,useHeliosRewindFailed, anduseHeliosSnapshotListhooks.
js-sdk · Multi-client connections
Breaking
- Publishing an input track is now explicit. Output tracks still stream automatically on connect, but
sendonly(input) tracks send nothing until your app callspublishTrack()(or renders<WebcamStream>). Apps that relied on input media flowing at connect must now publish explicitly once the connection isready. See Tracks.
New
- Output track pause/resume. New
pauseTrack()andresumeTrack()methods, plus anautoResumeTracksconnect option (defaulttrue), control when each output track streams. - Multi-client sessions. A single session can now back several connections at once.
connect()acceptssessionIdandconnectionIdoptions to attach to a session or connection your backend created.
Pricing
Changed
- Per-second and per-hour pricing in dollars. Model pricing is now displayed as US-dollar rates on the Pricing & Billing page.
Docs · Pricing & billing
New
- Pricing & billing docs. Published Pricing & Billing, covering session pricing, idle vs. active billing, and recoverable-state behavior.
- Beta status callouts. Added a banner across docs and the Overview noting that Reactor is in beta. APIs and pricing may evolve.
Authentication · API
New
- Token TTL with
expires_after. Auth tokens now carry anexpires_afterfield so clients can refresh proactively instead of waiting for a 401. See Authentication.
js-sdk · reactor-sdk · Concepts
New
- File uploads in the Python SDK.
reactor-sdknow supportsupload_file()returning aFileRefthat can be passed intosend_command(). - File uploads in the JavaScript SDK.
uploadFile()andFileRefare available in@reactor-team/js-sdkfor passing files (images, audio, blobs) as command arguments. - New concept page: File Uploads documents the upload-then-reference pattern in both SDKs.
API
Breaking
- Token endpoint is now POST. The auth-token endpoint moved from
GETtoPOSTto allow request-body parameters. Update any direct API callers; the SDKs handle this automatically once upgraded.
js-sdk 2.7 · reactor-sdk 0.4
Breaking
- New SDK protocol. Wire-level protocol overhaul shipped in
@reactor-team/js-sdk2.7 andreactor-sdk0.4. Older SDK versions will no longer connect. Upgrade to the latest release. - Removed
fetchInsecureToken()and JWT helpers. The development-only insecure token helpers were removed; all auth now flows through the standard token endpoint.
Improved
- Maple theme refresh. Docs site updated to Mintlify’s Maple theme with Lucide icons, new codeblock styling, and refreshed colors.
- Navigation split into separate “SDK” and “API Reference” tabs.
Helios
js-sdk 2.6.0
Breaking
- API renames in
@reactor-team/js-sdk2.6.0. Several public methods and types were renamed for consistency with the Python SDK. Update import paths and call sites.
Helios
New
- Helios launch. Reactor’s first interactive real-time video generation model, built on a 14B-parameter Diffusion Transformer. Produces a continuous infinite stream you can steer with prompts and reference images.
- Helios prompt guide. A dedicated Prompt Guide covering scene composition, transitions, and steering techniques.
Docs
Improved
- Renamed “Realtime AI” → “Realtime Video AI” across the docs to better reflect what Reactor does. No API or SDK changes.
reactor-sdk (Python)
New
- Python SDK launched.
reactor-sdkis now available on PyPI, async-first, with parity for sessions, commands, and message handling. See Using the SDK.
js-sdk
Breaking
sendCommand()replacessendMessage(). The command API was renamed to clarify the distinction between commands (client → model) and messages (model → client). Update allsendMessagecall sites. See Commands and messages.- Removed message queueing. Commands now have explicit
waitingstate instead of implicit queueing. Applications can decide whether to drop, replace, or buffer in-flight commands.
Authentication · API
Breaking
- JWT auth replaces
insecureApikey. All client connections now require a short-lived JWT minted server-side from your API key. TheinsecureApikeydevelopment flow is removed. - New API Reference section. Published a complete API Reference covering the
Reactorclass, React components, hooks, types, and events.
Docs
New
- Reactor docs site launched. Initial release with Overview and Quickstart. Ported from the legacy readme.io site.