# `Codex.Realtime.OpenAIWebSocket`
[🔗](https://github.com/nshkrdotcom/codex_sdk/blob/v0.16.1/lib/codex/realtime/openai_websocket.ex#L1)

WebSocket client for OpenAI Realtime API.

This module manages the WebSocket connection to OpenAI's Realtime API,
handling connection lifecycle, message parsing, and event dispatching.

## Architecture

The WebSocket client operates as a separate process that:

1. Establishes and maintains the WebSocket connection
2. Parses incoming JSON messages into structured events
3. Forwards events to the session process and any registered listeners
4. Sends outgoing messages (audio, user input, tool outputs, etc.)

## Usage

This module is typically not used directly. Instead, use `Codex.Realtime.Session`
which manages the WebSocket connection internally.

    {:ok, ws} = OpenAIWebSocket.start_link(
      session_pid: self(),
      config: %ModelConfig{api_key: "sk-..."},
      model_name: "gpt-4o-realtime-preview"
    )

    OpenAIWebSocket.send_message(ws, %{"type" => "response.create"})

# `outbound_frame`

```elixir
@type outbound_frame() ::
  :ping | :pong | {:ping | :pong, nil | binary()} | {:text | :binary, binary()}
```

# `send_frame_error`

```elixir
@type send_frame_error() ::
  %WebSockex.ConnError{__exception__: true, original: term()}
  | %WebSockex.FrameEncodeError{
      __exception__: true,
      close_code: term(),
      frame_payload: term(),
      frame_type: term(),
      reason: term()
    }
  | %WebSockex.InvalidFrameError{__exception__: true, frame: term()}
  | %WebSockex.NotConnectedError{__exception__: true, connection_state: term()}
```

# `t`

```elixir
@type t() :: %Codex.Realtime.OpenAIWebSocket{
  config: Codex.Realtime.Config.ModelConfig.t(),
  listeners: [pid()],
  session_pid: pid()
}
```

# `add_listener`

```elixir
@spec add_listener(pid(), pid()) :: :ok
```

Add a listener for events.

Listeners receive `{:model_event, event}` messages for all events.

# `close`

```elixir
@spec close(pid()) :: :ok
```

Gracefully close the websocket connection.

WebSockex does not support sending close frames via `send_frame/2`; the
websocket process has to initiate shutdown from its own callback context.

# `remove_listener`

```elixir
@spec remove_listener(pid(), pid()) :: :ok
```

Remove a listener.

# `send_frame`

```elixir
@spec send_frame(pid(), outbound_frame()) :: :ok | {:error, send_frame_error()}
```

Send a raw websocket frame through the underlying WebSockex client.

# `send_message`

```elixir
@spec send_message(pid(), map() | [map()]) :: :ok | {:error, send_frame_error()}
```

Send a message to the WebSocket.

Accepts a single message map or a list of message maps.

## Examples

    OpenAIWebSocket.send_message(ws, %{"type" => "response.create"})

    OpenAIWebSocket.send_message(ws, [
      %{"type" => "input_audio_buffer.append", "audio" => base64_audio},
      %{"type" => "input_audio_buffer.commit"}
    ])

# `start_link`

```elixir
@spec start_link(keyword()) :: {:ok, pid()} | {:error, term()}
```

Start the WebSocket connection.

## Options

  * `:session_pid` - Required. The session process to receive events.
  * `:config` - Required. The model configuration.
  * `:model_name` - Optional model name to use in the URL.

## Returns

  * `{:ok, pid}` on successful connection
  * `{:error, reason}` on failure

---

*Consult [api-reference.md](api-reference.md) for complete listing*
