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

# Client Constructor

RTVI projects implement a client instance that:

* Facilitates web requests to an endpoint you create.
* Dispatches single-turn actions to a HTTP bot service when disconnected.
* Provides methods that handle the connectivity state and real-time interaction with your bot service.
* Manages media transport (such as audio and video).
* Provides callbacks and events for handling bot messages and actions.
* Optionally configures your AI services and pipeline.

## RTVIClient

```javascript
import { RTVIClient } from "realtime-ai";
```

`RTVIClient` is a base class that serves as a template for building transport-specific implementations.

<Note>
  For connected use-cases, you must pass a transport instance to the constructor
  for your chosen protocol or provider. See [Transport](./transports) for more
  information.
</Note>

If you were looking to use WebRTC as a transport layer, you may use a provider like [Daily](https://www.daily.co). In this scenario, you'd construct a transport instance and pass it to the client accordingly:

```typescript
import { RTVIClient } from "realtime-ai";
import { DailyTransport } from "@daily-co/realtime-ai-daily";

const dailyTransport = new DailyTransport();
const rtviClient = new RTVIClient({
  transport: dailyTransport,
});
```

All transport packages (such as `DailyTransport`) extend from the `Transport` base class defined in RTVI core.
You can extend this class if you are looking to implement your own or add additional functionality.

## Example

<Tabs>
  <Tab title="Connected Example">
    ```typescript
    import { RTVIEvent, RTVIMessage, RTVIClient } from "realtime-ai";
    import { DailyTransport } from "@daily-co/realtime-ai-daily";

    const dailyTransport = new DailyTransport();

    const rtviClient = new RTVIClient({
      transport: dailyTransport,
      params: {
        baseUrl: "https://your-connect-end-point-here",
        services: {
          stt: "deepgram",
          llm: "together",
          tts: "cartesia",
        },
        config: [
          {
            service: "tts",
            options: [
              { name: "voice", value: "79a125e8-cd45-4c13-8a67-188112f4dd22" }
            ]
          },
          {
            service: "llm",
            options: [
              { name: "model", value: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo" },
              {
                name: "messages",
                value: [
                  {
                    role: "system",
                    content:
                      "You are a assistant called ExampleBot. You can ask me anything. Keep responses brief and legible. Your responses will be converted to audio, so please avoid using any special characters except '!' or '?'.",
                  }
                ]
              }
            ]
          }
        ]
      }
      enableMic: true,
      enableCam: false,
      timeout: 15 * 1000,
      callbacks: {
        onConnected: () => {
          console.log("[CALLBACK] User connected");
        },
        onDisconnected: () => {
          console.log("[CALLBACK] User disconnected");
        },
        onTransportStateChanged: (state: string) => {
          console.log("[CALLBACK] State change:", state);
        },
        onBotConnected: () => {
          console.log("[CALLBACK] Bot connected");
        },
        onBotDisconnected: () => {
          console.log("[CALLBACK] Bot disconnected");
        },
        onBotReady: () => {
          console.log("[CALLBACK] Bot ready to chat!");
        },
      },
    });

    try {
      await rtviClient.connect();
    } catch (e) {
      console.error(e.message);
    }

    // Events
    rtviClient.on(RTVIEvent.TransportStateChanged, (state) => {
      console.log("[EVENT] Transport state change:", state);
    });
    rtviClient.on(RTVIEvent.BotReady, () => {
      console.log("[EVENT] Bot is ready");
    });
    rtviClient.on(RTVIEvent.Connected, () => {
      console.log("[EVENT] User connected");
    });
    rtviClient.on(RTVIEvent.Disconnected, () => {
      console.log("[EVENT] User disconnected");
    });
    ```
  </Tab>

  <Tab title="Single-Turn Action Example">
    ```typescript
      import { RTVIClient } from "realtime-ai";

      const rtviClient = new RTVIClient({
        params: {
          baseUrl: "https://your-connect-end-point-here",
          services: {
            llm: "together",
          },
          config: [
            {
              service: "llm",
              options: [
                { name: "model", value: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo" },
                {
                  name: "messages",
                  value: [
                    {
                      role: "system",
                      content:
                        "You are a assistant called ExampleBot. You can ask me anything. Keep responses brief and legible.",
                    }
                  ]
                }
              ]
            }
          ]
        },
        callbacks: {
          onBotText: (text: BotLLMTextData) => {
            console.log("Text response:", text);
          },
        }
      });

      try {
        await rtviClient.action({
        service: "llm",
        action: "append_to_messages",
        arguments: [
          {
            name: "messages",
            value: [
              {
                role: "user",
                content: "tell me a joke",
              },
            ],
          },
        ],
      });
      } catch (e) {
        console.error(e.message);
      }

    ```
  </Tab>
</Tabs>

***

## API reference

### transport

<ParamField path="transport" type="Class<Transport>" default="undefined" required="true">
  Instance of `Transport` required to connect to your bot service (`rtviClient.connect()`). Transports define connectivity and state logic that manage the lifecycle of your session.
  Transports also define a protocol for message exchange between your client and bot service (such as [actions](./actions), or [generic messages](./messages).

  If your transport package (e.g.
  `@daily-co/realtime-ai-daily`) exports multiple transports classes, you can
  specify which to use here.

  ```typescript
  import { RTVIClient } from "realtime-ai";
  import { DailyTransport } from "@daily-co/realtime-ai-daily";

  const dailyTransport = new DailyTransport();
  const rtviClient = new RTVIClient({
    transport: dailyTransport,
  });
  ```
</ParamField>

### params

A client-side mutatable object that is used to configure how your client connects or triggers actions.

Parameters can be updated at any time during the client lifecycle.

<ParamField path="baseUrl" type="string" required>
  Base URL to a developer hosted API that exposes various endpoints to the RTVI
  application.
</ParamField>

<ParamField path="endpoints" type="Record<RTVIURLEndpoints, string>">
  Endpoints appended to your client base URL. RTVI will apply defaults if not provided.

  | Property         | Description                                                                                                                                                                                                   |
  | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `connect:string` | Developer hosted endpoint that triggers authentication, transport session creation and bot instantiation. Typically returns a valid authentication bundle required to join a session. Defaults to "connect/". |
  | `action:string`  | Developer hosted endpoint that triggers disconnected action for single-turn operations. Typically implemented as a HTTP Stream or Websocket. Defaults to "action/".                                           |

  You should ensure your endpoints have the necessary CORS headers set to allow requests from your client application.

  ```typescript
  const rtviClient = RTVIClient({
    params: {
      baseUrl: "https://www.example.com",
      endpoints: {
        connect: "/connect", // https://www.example.com/connect
        action: "/action", // https://www.example.com/action
      },
    },
  });
  ```
</ParamField>

<ParamField path="requestData" type="object">
  Custom request data that is passed to the `baseUrl` with any web request. This can be used to pass additional data to your server-side endpoint.

  ```typescript
  const rtviClient = RTVIClient({
    params: {
      baseUrl: "https://www.example.com",
      requestData: {
        customData: "my custom data",
      },
    },
  });

  await rtviClient.connect();

  // POST https://www.example.com/connect
  // --data '{ "customData": "my custom data" }'

  await rtviClient.disconnect();

  rtviClient.params.requestData = {
    customData: "my updated custom data",
  };

  await rtviClient.connect();

  // POST https://www.example.com/connect
  // --data '{ "customData": "my updated custom data"}'
  ```
</ParamField>

<ParamField path="headers" type="Headers">
  Optional `Headers` object that is used when making requests to the `baseUrl`.
</ParamField>

<ParamField path="config" type="Array <RTVIClientConfigOption[]>">
  Pipeline RTVI configuration passed to your bot pipeline. Must contain a valid `RTVIClientConfigOption[]` array.

  Client configuration is optional and can be passed directly to the bot via your server-side endpoint (where sensitive information can be provided, such as API keys.)

  The service order of your configuration array is important. See [configuration](./configuration).
</ParamField>

### Optional properties

<ParamField path="callbacks" type="RTVIEventCallbacks">
  Map of callback functions. See [callbacks](./callbacks).
</ParamField>

<ParamField path="timeout" type="number" default="undefined">
  Time (in milleseconds) to wait for the bot to enter a ready state after
  calling `connect()`. If the timeout period is elapsed, the client will return
  a `ConnectionTimeoutError` error and disconnect from the transport.
</ParamField>

<ParamField path="enableMic" type="boolean" default="true">
  Enable user's local microphone device.
</ParamField>

<ParamField path="enableCamera" type="boolean" default="false">
  Enable user's local webcam device. Note: please ensure you are using a
  transport package that supports video.
</ParamField>

### Custom Connect Handler

Calling `rtviClient.connect()` will trigger a default fetch query to your `baseUrl/connect` endpoint. If you need to override this behaviour, you can provide a custom connect handler.

<ParamField path="customConnectHandler" type="(params, timeout, abortController) => Promise<void>">
  Override the default fetch query called by `rtviClient.connect()`. If your server-side infrastructure has specific requirements, you can provide custom behaviour here.

  * `params:RTVIClientParams` Params provided in client constructor.
  * `timeout:Timeout | undefined` Start timeout. You should clear this once your method resolves e.g. `clearTimeout(timeout)`.
  * `abortController:AbortController` - Aborting connection via `abortController.abort()` will reject the inflight request, clear the connection timeout and set the client to an error state.

  ```typescript
  const rtviClient = new RTVIClient({
    // ...
    customConnectHandler: async (
      params: RTVIClientParams,
      timeout: number | undefined,
      abortController: AbortController
    ): Promise<void> => {
      const connectUrl = rtviClient.constructUrl(params.endpoints.connect);
      return await fetch(connectUrl, {
        method: "POST",
        mode: "cors",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ...`,
        },
        body: JSON.stringify({
          services: {...},
          config: [...],
          // ... your custom body params here
        }),
        signal: abortController?.signal,
      }).then((res) => {
        clearTimeout(timeout); // Clear the start timeout (if set)

        if (res.ok) {
          return res.json();
        }
        return Promise.reject(res);
      });
    },
  });
  ```
</ParamField>
