---
sidebar_label: 'Create Custom Adapters'
---

import {PlatformSelector} from '@site/src/components/PlatformSelector/PlatformSelector';
import CustomAdapterReactJs from './_custom-adapter-example/#react.mdx';
import CustomAdapterJavascript from './_custom-adapter-example/#js.mdx';

# Create Custom Adapters

If you're building your APIs and you would like to use `NLUX` as the UI for your own AI chatbot,
you can do so by creating a custom adapter.

An adapter is a component that connects `NLUX` an API. It receives messages from `NLUX` and sends them to the API.
It also receives responses from the API and sends them to `NLUX` in a format that can be displayed in the chat UI.

## Creating a Custom Adapter

There are 2 types of custom adapters that you can create:

* Streaming Adapters
* Promise Adapters

## Streaming Adapters

Streaming adapters are used when the API sends responses in a stream (e.g. WebSockets, or Server-Sent Events).

The advantage of using a streaming adapter is that **the chat UI will be updated in real-time while the LLM is still
generating text**. This is particularly useful if the API takes a long time to process a request and sends responses
in a stream. Most major LLM APIs (e.g. OpenAI, Anthropic) support streaming responses.

To implement a custom streaming adapter for `NLUX`, you need to implement the following interface:

```typescript
interface ChatAdapter {
    streamText: (
        message: string,
        observer: StreamingAdapterObserver,
        extras: AdapterExtras,
    ) => void;
}
```

The `streamText` method takes 2 parameters:

* `message` - The prompt message typed by the user, to be sent to the API.
* `observer` - An observer that will receive the responses from the API and pass them to `NLUX`.

Below is the definition of the `StreamingAdapterObserver` interface:

```typescript
interface StreamingAdapterObserver {
    next: (partialResponse: string) => void;
    error: (error: Error) => void;
    complete: () => void;
}
```

You can call the `next` method of the observer as responses are received from the API.
The `complete` method should be called when the API has finished sending responses, and
The `error` method should be called if an error occurs.

### Example: Streaming Adapter

Let's say we want to create an adapter for a custom API that sends responses in a stream.<br />
This eventual API has a WebSocket endpoint that can be used to send messages and receive responses.

We can create a streaming adapter for this API by implementing the `ChatAdapter` interface's `streamText` method
as follows:

```typescript
import {ChatAdapter, StreamingAdapterObserver} from '@nlux/core';

export const myCustomAdapter: ChatAdapter = {
    streamText: (message: string, observer: StreamingAdapterObserver): void => {
        const socket = new WebSocket('ws://localhost:8080');
        
        // We register listeners for the WebSocket events here
        // and call the observer methods accordingly
        socket.onmessage = (event) => observer.next(event.data);
        socket.onclose = () => observer.complete();
        socket.onerror = (error) => observer.error(error);
        
        // This is where we send the user message to the API
        socket.send(message);
    }
}
```

Streaming adapters can also be used with APIs that send responses as Server-Sent Events (SSE).
All the examples on this website use this approach.

## Promise Adapters

Promise adapters can be used when the API sends responses in a single request (e.g. REST APIs).

The advantage of using a promise adapter is that **it's easier to implement**.

To implement a custom promise adapter for `NLUX`, you need to implement the following interface:

```typescript
interface ChatAdapter {
    fetchText(message: string, extras: AdapterExtras): Promise<string>;
}
```

The `fetchText` method takes 1 parameter:

* `message` - The prompt message typed by the user, to be sent to the API.

The `fetchText` method should return a promise that resolves to the response from the API.

### Example: Promise Adapter

Let's say we want to create a promise adapter for a custom API that sends responses in a single request.

The API has a REST endpoint that we can use to send messages and receive responses.

We can create a promise adapter for this API by implementing the `PromiseAdapter` interface:

```typescript
import {ChatAdapter} from '@nlux/core';

export const myCustomAdapter: ChatAdapter = {
    fetchText: (message: string, extras: AdapterExtras): Promise<string> => {
        return fetch('http://localhost:8080', {
            method: 'POST',
            body: JSON.stringify({message})
        })
            .then(response => response.json())
            .then(json => json.message);
    }
}
```

## Using Custom Adapters

Once you have created a custom adapter, you can use it to create a chat component and render it in the DOM:

The same custom adapter can be used with the React and JavaScript versions of `NLUX`.

### Example: Using a Custom Adapter

<PlatformSelector reactJs={CustomAdapterReactJs} javascript={CustomAdapterJavascript}/>

You can refer to the Getting Started guides for [React](/learn/get-started?platform=react-js) and
[JavaScript](/learn/get-started?platform=javascript) for more details on how to use `NLUX`.
