> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reactor.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# Reactor

> The base Python class for connecting to any Reactor model

`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`**:

```python Inheritance theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
class HeliosModel(Reactor): ...
```

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](/sdk-reference/using-the-sdk) for when each path makes sense.

For the list of commands and events a specific model accepts, see the [Model API Reference](/model-api-reference/overview).

## Constructor

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
Reactor(
    model_name: str,
    api_key: str | None = None,
    api_url: str = "https://api.reactor.inc",
    local: bool = False,
)
```

<ParamField path="model_name" type="str" required>
  The name of the model to connect to.
</ParamField>

<ParamField path="api_key" type="str">
  Your Reactor API key. The SDK automatically exchanges this for a token during `connect()`. Required unless `local=True`.
</ParamField>

<ParamField path="api_url" type="str" default="https://api.reactor.inc">
  The API URL. Ignored if `local=True`.
</ParamField>

<ParamField path="local" type="bool" default="False">
  If `True`, connects to a local runtime at `http://localhost:8080`. No API key required.
</ParamField>

```python Example theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
from reactor_sdk import Reactor

reactor = Reactor(model_name="your-model-name", api_key="rk_...")
```

The `Reactor` class also supports `async with` for automatic cleanup:

```python Context manager theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
from reactor_sdk import Reactor

async with Reactor(model_name="your-model-name", api_key="rk_...") as reactor:
    await reactor.connect()
    await reactor.send_command("start", {})
```

***

## Methods

### `connect()`

Establishes a connection to the coordinator, waits for GPU assignment, and opens a WebRTC connection to the model. If `api_key` was provided, fetches a token first.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.connect() -> None
```

**Raises:** `RuntimeError` if authentication fails or if already connected.

***

### `disconnect()`

Closes the connection.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.disconnect(recoverable: bool = False) -> None
```

<ParamField path="recoverable" type="bool" default="False">
  If `True`, the session is kept alive on the server and can be resumed with `reconnect()`. If `False`, the session is terminated.
</ParamField>

***

### `reconnect()`

Reconnects to an existing session after a recoverable disconnect.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.reconnect() -> None
```

Requires an active `session_id` from a previous connection.

***

### `send_command()`

Sends a command to the model.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.send_command(command: str, data: Any) -> None
```

<ParamField path="command" type="str" required>
  The command name. Must match a command defined on the model.
</ParamField>

<ParamField path="data" type="dict" required>
  The command payload. Shape depends on the command.
</ParamField>

```python Example theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.send_command("set_prompt", {"prompt": "a mountain landscape"})
```

You can also pass [`FileRef`](/sdk-reference/python/types#fileref) values from [`upload_file()`](/sdk-reference/python/reactor#upload_file) as parameters. See [File Uploads](/concepts/file-uploads) for details.

***

### `upload_file()`

Uploads a file and returns a [`FileRef`](/sdk-reference/python/types#fileref) that can be passed into `send_command()`.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.upload_file(
    file: BinaryIO | bytes | str | os.PathLike,
    *,
    name: str | None = None,
    mime_type: str | None = None,
) -> FileRef
```

<ParamField path="file" type="BinaryIO | bytes | str | PathLike" required>
  The file to upload. Accepts a file path, raw bytes, or a file-like object opened in binary mode.
</ParamField>

<ParamField path="name" type="str">
  Custom filename. Inferred from the file path or file object when not given. Defaults to `"upload"` for raw bytes.
</ParamField>

<ParamField path="mime_type" type="str">
  MIME type. Guessed from the filename when not given. Defaults to `"application/octet-stream"`.
</ParamField>

```python Example theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
ref = await reactor.upload_file("photo.jpg")
await reactor.send_command("set_image", {"image": ref})
```

<Note>
  Can only be called when the status is `READY`.
</Note>

***

### `publish_track()`

Publishes a named media track to the model.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.publish_track(name: str, track: MediaStreamTrack) -> None
```

<ParamField path="name" type="str" required>
  Track name. Must match a `sendonly` track name from the model's capabilities.
</ParamField>

<ParamField path="track" type="MediaStreamTrack" required>
  An `aiortc.MediaStreamTrack` to publish.
</ParamField>

***

### `unpublish_track()`

Stops publishing a named track to the model.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
await reactor.unpublish_track(name: str) -> None
```

<ParamField path="name" type="str" required>
  The name of the track to stop publishing.
</ParamField>

***

### `set_frame_callback()`

Sets a callback to receive video frames as NumPy arrays. Equivalent to `@reactor.on_frame`.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.set_frame_callback(callback: FrameCallback | None) -> None
```

<ParamField path="callback" type="FrameCallback | None" required>
  A function that receives frames as `(H, W, 3)` uint8 RGB NumPy arrays. Pass `None` to stop receiving frames.
</ParamField>

***

### `on()`

Registers an event handler.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.on(event: ReactorEvent, handler: Callable) -> None
```

***

### `off()`

Removes an event handler.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.off(event: ReactorEvent, handler: Callable) -> None
```

***

### `get_status()`

Returns the current connection status.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_status() -> ReactorStatus
```

Returns `ReactorStatus.DISCONNECTED`, `CONNECTING`, `WAITING`, or `READY`.

***

### `get_state()`

Returns the current status and last error.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_state() -> ReactorState
```

***

### `get_session_id()`

Returns the current session ID, or `None` if not connected.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_session_id() -> str | None
```

***

### `get_last_error()`

Returns the most recent error, or `None` if no errors have occurred.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_last_error() -> ReactorError | None
```

***

### `get_capabilities()`

Returns the model's capabilities (tracks, commands, emission FPS), or `None` if not yet connected.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_capabilities() -> Capabilities | None
```

***

### `get_session_info()`

Returns the full session response from the coordinator, or `None` if not connected.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_session_info() -> CreateSessionResponse | None
```

***

### `get_remote_tracks()`

Returns all remote tracks received from the model, keyed by track name.

```python Signature theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
reactor.get_remote_tracks() -> dict[str, MediaStreamTrack]
```

***

## Events

| Event                          | Payload                                | Description                                        |
| ------------------------------ | -------------------------------------- | -------------------------------------------------- |
| `"status_changed"`             | `ReactorStatus`                        | Connection status changed                          |
| `"session_id_changed"`         | `str \| None`                          | Session ID changed                                 |
| `"message"`                    | `Any`                                  | Application message from the model                 |
| `"runtime_message"`            | `Any`                                  | Internal platform message                          |
| `"track_received"`             | `(name: str, track: MediaStreamTrack)` | Named track received                               |
| `"error"`                      | `ReactorError`                         | Error occurred                                     |
| `"session_expiration_changed"` | `float \| None`                        | Session expiration time updated                    |
| `"capabilities_received"`      | `Capabilities`                         | Model capabilities received after session creation |

<Note>
  Python events use `snake_case` (e.g., `"status_changed"`) while the JavaScript SDK uses `camelCase` (e.g., `"statusChanged"`).
</Note>
