@nlux/core
Version:
nlux is JavaScript and React library for building conversational AI interfaces, with support for OpenAI, Hugging Face, and more.
1,248 lines (1,210 loc) • 75 kB
TypeScript
/**
* A single item in the conversation.
* This can be a message from the user, the assistant, or a system message.
*
* - `role: 'assistant'`: A message from the assistant (an AI response).
* The message type is generic and should match the generic type `AiMsg` used across the component.
* The `serverResponse` field is optional and can be used to store the full response received from the server.
*
* - `role: 'user'`: A message from the user.
* This is typically a string representing the prompt typed by the user.
*
* - `role: 'system'`: A system message.
* This message is not displayed in the UI, but it will be used to when sending the conversation history to the AI.
*/
type ChatItem$1<AiMsg = string> = {
role: 'assistant';
message: AiMsg;
serverResponse?: string | object | undefined;
} | {
role: 'user';
message: string;
} | {
role: 'system';
message: string;
};
/**
* Additional data sent to the adapter when a message is sent.
*/
type ChatAdapterExtras$1<AiMsg = string> = {
/**
* This attribute contains the properties used with the AiChat component.
*/
aiChatProps: AiChatPropsInEvents<AiMsg>;
/**
* This attribute contains the conversation history.
* It's only included if the `conversationOptions.historyPayloadSize` is set to a positive number or 'all'.
*/
conversationHistory?: ChatItem$1<AiMsg>[];
/**
* This attribute contains the unique identifier of the context instance.
* It's only included if a context instance is used with the AiChat component.
* This can be used to send the context ID to the API and get a response that is specific to the context instance.
*/
contextId?: string;
/**
* This contains the headers that implementers can use to send additional data such as authentication headers.
*/
headers?: Record<string, string>;
};
/**
* This type is used to indicate the mode in which the adapter should request data from the API.
*/
type DataTransferMode$1 = 'stream' | 'batch';
/**
* The type for the function used to submit a message to the API in stream mode.
*
* @param {string} message
* @param {StreamingAdapterObserver} observer
* @param {ChatAdapterExtras} extras
*/
type StreamSend<AiMsg = string> = (message: string, observer: StreamingAdapterObserver$1<AiMsg>, extras: ChatAdapterExtras$1<AiMsg>) => void;
/**
* The type for the function used to submit a message to the API in batch mode.
* It should return a promise that resolves to the response from the API.
*
* @param `string` message
* @param `ChatAdapterExtras` extras
* @returns Promise<string>
*/
type BatchSend<AiMsg = string> = (message: string, extras: ChatAdapterExtras$1<AiMsg>) => Promise<AiMsg>;
/**
* This interface exposes methods that should be implemented by any chat adapter to connect the AiChat component
* to any API or AI backend. Chat adapters can be used to request data from the API in batch mode or stream mode.
*
* The difference between this and the `AssistAdapter` interface is that this adapter can only return a text response
* to be displayed to the user. It cannot return a task to be executed by the client. If you are using the `AiChat`
* component in co-pilot mode, you should use the `AssistAdapter` interface instead.
*/
interface ChatAdapter<AiMsg = string> {
/**
* This method should be implemented by any adapter that wants to request data from the API in batch mode.
* It should return a promise that resolves to the response from the API.
* Either this method or `streamText` (or both) should be implemented by any adapter.
*
* @param `string` message
* @param `ChatAdapterExtras` extras
* @returns Promise<string>
*/
batchText?: BatchSend<AiMsg>;
/**
* This method should be implemented by any adapter to be used with nlux.
* Either this method or `batchText` (or both) should be implemented by any adapter.
*
* @param {string} message
* @param {StreamingAdapterObserver} observer
* @param {ChatAdapterExtras} extras
*/
streamText?: StreamSend<AiMsg>;
}
/**
* This interface is used to capture the stream of data being generated by the API and send it to the AiChat
* user interface as it's being generated.
*/
interface StreamingAdapterObserver$1<ChunkType = string> {
/**
* This method should be called by the adapter when it has completed sending data to the AiChat user interface.
* This will result in the AiChat component removing the loading indicator and resetting the conversation
* text input.
*/
complete(): void;
/**
* This method should be called by the adapter when it has an error to send to the AiChat user interface.
* This will result in the AiChat component displaying an error message to the user, resetting the
* conversation text input, removing the loading indicator, removing the message sent from the conversation.
*
* The error will be logged to the console, but it will not be displayed to the user. A generic error message
* will be displayed to the user instead.
*
* @param {Error} error
*/
error(error: Error): void;
/**
* This method should be called by the adapter when it has new data to send to the AiChat user interface.
* @param {ChunkType} chunk being sent as part of the stream.
*/
next(chunk: ChunkType): void;
}
/**
* This type is used to indicate the mode in which the adapter should request data from the API.
*/
type DataTransferMode = 'stream' | 'batch';
/**
* This interface is used to capture the stream of data being generated by the API and send it to the AiChat
* user interface as it's being generated.
*/
interface StreamingAdapterObserver<ChunkType = string> {
/**
* This method should be called by the adapter when it has completed sending data to the AiChat user interface.
* This will result in the AiChat component removing the loading indicator and resetting the conversation
* text input.
*/
complete(): void;
/**
* This method should be called by the adapter when it has an error to send to the AiChat user interface.
* This will result in the AiChat component displaying an error message to the user, resetting the
* conversation text input, removing the loading indicator, removing the message sent from the conversation.
*
* The error will be logged to the console, but it will not be displayed to the user. A generic error message
* will be displayed to the user instead.
*
* @param {Error} error
*/
error(error: Error): void;
/**
* This method should be called by the adapter when it has new data to send to the AiChat user interface.
* @param {ChunkType} chunk being sent as part of the stream.
*/
next(chunk: ChunkType): void;
}
/**
* This type represents the information that the AiChat needs to know about an adapter.
* It is used to determine which adapters are available and what capabilities they have.
*/
type StandardAdapterInfo$1 = Readonly<{
id: string;
capabilities: Readonly<{
chat: boolean;
fileUpload: boolean;
textToSpeech: boolean;
speechToText: boolean;
}>;
}>;
/**
* This interface is used by standard adapters provided by nlux to communicate with the AiChat component.
*/
interface StandardChatAdapter$1<AiMsg = string> {
batchText(message: string, extras: ChatAdapterExtras$1<AiMsg>): Promise<string | object | undefined>;
get dataTransferMode(): DataTransferMode;
get id(): string;
get info(): StandardAdapterInfo$1;
preProcessAiBatchedMessage(message: string | object | undefined, extras: ChatAdapterExtras$1<AiMsg>): AiMsg | undefined;
preProcessAiStreamedChunk(chunk: string | object | undefined, extras: ChatAdapterExtras$1<AiMsg>): AiMsg | undefined;
streamText(message: string, observer: StreamingAdapterObserver<string | object | undefined>, extras: ChatAdapterExtras$1<AiMsg>): void;
}
/**
* The base interface for creating a new instance of a StandardChatAdapter.
* Adapter builders can extend this interface to add additional methods for configuration.
*/
interface ChatAdapterBuilder<AiMsg> {
create(): StandardChatAdapter$1<AiMsg>;
}
/**
* This interface is used by standard adapters provided by nlux to communicate with the AiChat component.
*/
interface StandardChatAdapter<AiMsg = string> {
batchText(message: string, extras: ChatAdapterExtras$1<AiMsg>): Promise<string | object | undefined>;
get dataTransferMode(): DataTransferMode;
get id(): string;
get info(): StandardAdapterInfo$1;
preProcessAiBatchedMessage(message: string | object | undefined, extras: ChatAdapterExtras$1<AiMsg>): AiMsg | undefined;
preProcessAiStreamedChunk(chunk: string | object | undefined, extras: ChatAdapterExtras$1<AiMsg>): AiMsg | undefined;
streamText(message: string, observer: StreamingAdapterObserver<string | object | undefined>, extras: ChatAdapterExtras$1<AiMsg>): void;
}
/**
* A single item in the conversation.
* This can be a message from the user, the assistant, or a system message.
*
* - `role: 'assistant'`: A message from the assistant (an AI response).
* The message type is generic and should match the generic type `AiMsg` used across the component.
* The `serverResponse` field is optional and can be used to store the full response received from the server.
*
* - `role: 'user'`: A message from the user.
* This is typically a string representing the prompt typed by the user.
*
* - `role: 'system'`: A system message.
* This message is not displayed in the UI, but it will be used to when sending the conversation history to the AI.
*/
type ChatItem<AiMsg = string> = {
role: 'assistant';
message: AiMsg;
serverResponse?: string | object | undefined;
} | {
role: 'user';
message: string;
} | {
role: 'system';
message: string;
};
interface ComposerOptions {
/**
* Indicates whether the prompt input field should be focused when the prompt is shown.
* @default false
*/
autoFocus?: boolean;
/**
* This will override the disabled state of the submit button when the composer is in 'typing' status.
* It will not have any impact in the composer 'submitting-prompt' and 'waiting' statuses, as the submit button
* is always disabled in these statuses.
*
* @default: Submit button is only enabled when the message is not empty.
*/
disableSubmitButton?: boolean;
/**
* Indicates whether the stop button should be hidden.
*
* @default false
*/
hideStopButton?: boolean;
/**
* The placeholder message to be displayed in the prompt input field when empty.
*/
placeholder?: string;
/**
* The shortcut to submit the prompt message.
*
* - `Enter`: The user can submit the prompt message by pressing the `Enter` key. In order to add a new line, the
* user can press `Shift + Enter`.
* - `CommandEnter`: When this is used, the user can submit the prompt message by pressing `Ctrl + Enter` on
* Windows/Linux or `Cmd + Enter` on macOS. In order to add a new line, the user can press `Enter`.
*
* @default 'Enter'
*/
submitShortcut?: 'Enter' | 'CommandEnter';
}
/**
* This represents a single item displayed in the chat UI while the conversation has not started yet.
*
*/
type ConversationStarter = {
/**
* The prompt to type in the composer input and submit to start the conversation.
*/
prompt: string;
/**
* An optional label to display inside the conversation starter option button.
*/
label?: string;
/**
* An optional icon to display inside the conversation starter option button.
* This could either be a URL to an image or an HTML element.
*/
icon?: string | Readonly<HTMLElement>;
};
type HistoryPayloadSize = number | 'max';
type ConversationLayout = 'bubbles' | 'list';
interface ConversationOptions {
/**
* Indicates whether the conversation should be scrolled to the bottom when a new message is added.
*
* @default true
*/
autoScroll?: boolean;
/**
* Suggested prompts to display in the UI to help the user start a conversation.
* Conversation starters are only displayed when the conversation is empty, and no conversation history is present.
*/
conversationStarters?: ConversationStarter[];
/**
* Indicates the number of messages from conversation history that should be sent to the backend with each message.
* For custom adapters, the history will be available as part of `extras.conversationHistory` attribute.
* For standard adapters, the history will be automatically handled by the adapter.
*
* By default, the entire conversation history is sent with each message.
* Set to `0` to disable sending conversation history with each message.
* Or set to a positive integer to send a specific number of messages.
*
* @default 'max'
*/
historyPayloadSize?: HistoryPayloadSize;
/**
* Indicates how items in the conversation should be displayed.
*
* - `list`: Chat items are displayed as a list with the AI responses underneath each user message.
* - `bubbles`: Items are displayed as chat bubbles with the prompts on the right and the AI messages on the left.
*
* @default 'bubbles'
*/
layout?: ConversationLayout;
/**
* Indicates whether the welcome message should be displayed when no conversation history is provided.
* The welcome message consists of:
* - The assistant's name and avatar
* - The assistant's tagline as configured in the `personaOptions`
*
* When no assistant persona is provided, the welcome message will be the NLUX logo.
*/
showWelcomeMessage?: boolean;
}
type DisplayOptions = {
/**
* The theme ID to use.
* This should be the ID of a theme that has been loaded into the page.
*/
themeId?: string;
/**
* Color scheme for the component.
* This can be 'light', 'dark', or 'auto'.
*
* If 'auto' is used, the component will automatically switch between 'light' and 'dark' based on the user's
* operating system preferences (if it can be detected), otherwise it will default to 'light'.
*
* @default 'auto'
*/
colorScheme?: 'light' | 'dark' | 'auto';
/**
* The width of the component.
*/
width?: number | string;
/**
* The height of the component.
*/
height?: number | string;
};
/**
* A type representing a function to use as HTML sanitizer.
* This type can be passed to markdown parser, to be used to sanitize generated
* HTML before appending it to the document.
*/
type SanitizerExtension = (html: string) => string;
type Highlighter = (input: string, language: string) => string;
type HighlighterColorMode = 'dark' | 'light';
type CreateHighlighterOptions = {
language?: string;
colorMode?: HighlighterColorMode;
};
interface HighlighterExtension {
createHighlighter(options?: CreateHighlighterOptions): Highlighter;
highlightingClass(language?: string): string;
}
/**
* Props for the custom function that renders a message sent by the server in batch mode.
* @template AiMsg The type of the message received from the AI. Defaults to string for standard NLUX adapters.
*
* @property {string} uid The unique identifier of the message.
* @property {'batch'} dataTransferMode The data transfer mode used by the adapter.
* @property {'complete'} status The status of the message.
*
* @property {AiMsg} content The content of the message. The content is a single message.
* @property {unknown} serverResponse The raw server response. The server response is a single object or string
* representing the raw response received from the server.
*/
type ResponseRendererProps<AiMsg> = {
uid: string;
dataTransferMode: 'stream' | 'batch';
status: 'streaming' | 'complete';
content: [AiMsg];
serverResponse: unknown[];
};
type ResponseRenderer<AiMsg> = (props: ResponseRendererProps<AiMsg>) => HTMLElement | null;
type PromptRendererProps = {
uid: string;
prompt: string;
};
type PromptRenderer = (props: PromptRendererProps) => HTMLElement | null;
type MessageOptions<AiMsg = string> = {
/**
* Highlighter extension for code blocks inside messages.
*/
syntaxHighlighter?: HighlighterExtension;
/**
* Custom function to sanitize the HTML content of the messages. This function is called before any HTML content
* is rendered in the chat.
*
* @param {string} html
* @returns {string}
*/
htmlSanitizer?: SanitizerExtension;
/**
* Indicates the target of the links in the markdown messages.
* - 'blank': Open links in a new tab.
* - 'self': Open links in the same tab.
*
* @default 'blank'
*/
markdownLinkTarget?: 'blank' | 'self';
/**
* Indicates whether the copy button should be shown for code blocks.
*
* @default true
*/
showCodeBlockCopyButton?: boolean;
/**
* Indicates whether the streaming animation should be skipped.
*
* @default false
*/
skipStreamingAnimation?: boolean;
/**
* The interval in milliseconds at which new characters are added when a message is being generated and
* streamed to the user.
*
* @default 10
*/
streamingAnimationSpeed?: number;
/**
* In streaming data transfer mode, this represents the wait time in milliseconds after last chunk of data
* is received before marking the streaming as complete. This can be used to prevent the streaming from being
* marked as complete too early.
*
* If set to 'never', the streaming will never be automatically be marked as complete. It will be up to the
* adapter to manually mark the streaming as complete by calling the `observer.complete()` method.
*
* @default 2000
*/
waitTimeBeforeStreamCompletion?: number | 'never';
/**
* Custom function to render the message received from the AI.
*/
responseRenderer?: ResponseRenderer<AiMsg>;
/**
* Custom function to render the message sent by the user.
*/
promptRenderer?: PromptRenderer;
/**
* Indicates whether the user should be able to edit the message after sending it.
* Editing a message will replace the original message and will remove all subsequent messages in the conversation.
*
* @default false
*/
editableUserMessages?: boolean;
};
interface AssistantPersona {
avatar: string | Readonly<HTMLElement>;
name: string;
tagline?: string;
}
interface UserPersona {
avatar: string | Readonly<HTMLElement>;
name: string;
}
interface PersonaOptions {
assistant?: AssistantPersona;
user?: UserPersona;
}
declare const NLErrors: {
'data-transfer-mode-not-supported': string;
'no-data-transfer-mode-supported': string;
'connection-error': string;
'invalid-credentials': string;
'invalid-api-key': string;
'http-server-side-error': string;
'http-client-side-error': string;
'failed-to-load-content': string;
'failed-to-stream-content': string;
'failed-to-stream-server-component': string;
'failed-to-render-content': string;
};
type NLErrorId = keyof typeof NLErrors;
/**
* These are the props that are used internally by the AiChat component.
*/
type AiChatInternalProps<AiMsg> = {
adapter: ChatAdapter<AiMsg> | StandardChatAdapter<AiMsg>;
className?: string;
events?: EventsConfig<AiMsg>;
initialConversation?: ChatItem<AiMsg>[];
displayOptions: DisplayOptions;
personaOptions: PersonaOptions;
composerOptions: ComposerOptions;
conversationOptions: ConversationOptions;
messageOptions: MessageOptions<AiMsg>;
};
/**
* These are the props that are exposed to the user of the AiChat component.
*/
type AiChatProps<AiMsg = string> = {
adapter: ChatAdapter<AiMsg> | StandardChatAdapter<AiMsg>;
className?: string;
events?: EventsConfig<AiMsg>;
initialConversation?: ChatItem<AiMsg>[];
composerOptions?: ComposerOptions;
conversationOptions?: ConversationOptions;
messageOptions?: MessageOptions<AiMsg>;
personaOptions?: PersonaOptions;
displayOptions?: DisplayOptions;
};
/**
* When sending props to event callbacks, we exclude the adapter and events properties.
* This is because they are not serializable and because the events are already being called.
*/
type AiChatPropsInEvents<AiMsg = string> = Omit<AiChatProps<AiMsg>, 'adapter' | 'events'>;
/**
* This type represents the props that can be updated on the AiChat component, after it has been initialized.
* It excludes the initialConversation property because it's only used during initialization and cannot be updated.
*/
type UpdatableAiChatProps<AiMsg> = Partial<Omit<AiChatProps<AiMsg>, 'initialConversation'>>;
type MessageSentEventDetails = {
uid: string;
message: string;
};
type MessageStreamStartedEventDetails = {
uid: string;
};
type ServerComponentStreamStartedEventDetails = {
uid: string;
};
type ServerComponentRenderedEventDetails = {
uid: string;
};
type MessageRenderedEventDetails<AiMsg = string> = {
uid: string;
message?: AiMsg;
};
type MessageReceivedEventDetails<AiMsg = string> = {
uid: string;
message: AiMsg;
};
type ErrorEventDetails = {
errorId: NLErrorId;
message: string;
errorObject?: Error;
};
type ReadyEventDetails<AiMsg = string> = {
aiChatProps: AiChatPropsInEvents<AiMsg>;
};
type PreDestroyEventDetails<AiMsg = string> = {
aiChatProps: AiChatPropsInEvents<AiMsg>;
conversationHistory: Readonly<ChatItem<AiMsg>[]>;
};
/**
* The callback for when an error event is emitted.
*
* @param errorDetails The details of the error event such as the error message and the error id.
*/
type ErrorCallback = (errorDetails: ErrorEventDetails) => void;
/**
* The callback for when a message is sent.
* This is called when the chat component sends the message to the adapter.
*
* @param message The message that was sent.
*/
type MessageSentCallback = (event: MessageSentEventDetails) => void;
/**
* The callback for when a response starts streaming from the adapter.
* This is called when the chat component receives the first part of the response from the adapter.
* This does not mean that the message has been rendered yet. You should use the messageRendered event
* if you want to know when the message has been rendered.
*
* @param event The event details such as the uid of the message.
*/
type MessageStreamStartedCallback = (event: MessageStreamStartedEventDetails) => void;
/**
* The callback for when a server component stream starts.
* This is used with React Server Component adapters to trigger an event when the component is about
* to get mounted.
*/
type ServerComponentStreamStartedCallback = (event: ServerComponentStreamStartedEventDetails) => void;
/**
* The callback for when a server component is loaded and successfully rendered on the screen.
*
* @param event The event details such as the uid of the message.
*/
type ServerComponentRenderedCallback = (event: ServerComponentRenderedEventDetails) => void;
/**
* The callback for when a message is received.
* This is called when the chat component receives the full response from the adapter.
* This does not mean that the message has been rendered yet. You should use the messageRendered
* event if you want to know when the message has been rendered.
*
* @param event The event details such as the uid of the message and the message content.
*/
type MessageReceivedCallback<AiMsg = string> = (event: MessageReceivedEventDetails<AiMsg>) => void;
/**
* The callback for when a message is fully rendered on the screen.
* This event is only relevant when the user is using the NLUX markdown renderer.
* If the user is using a custom renderer and directly accessing the props.content property to render the message,
* this event will not be relevant.
*
* @param event The event details such as the uid of the message.
*/
type MessageRenderedCallback<AiMsg = string> = (event: MessageRenderedEventDetails<AiMsg>) => void;
/**
* The callback for when the chat component is ready.
* This is called when the chat component is fully initialized and ready to be used.
*
* @param readyDetails The details of the ready event such as the AiChatProps used to initialize the chat component.
*/
type ReadyCallback<AiMsg = string> = (readyDetails: ReadyEventDetails<AiMsg>) => void;
/**
* The callback for when the chat component is about to be destroyed.
* This is called when the chat component is about to be destroyed and unmounted from the DOM.
*
* @param preDestroyDetails The details of the pre-destroy event such as the AiChatProps used to initialize the chat
* component and the conversation history.
*/
type PreDestroyCallback<AiMsg = string> = (preDestroyDetails: PreDestroyEventDetails<AiMsg>) => void;
type EventsMap<AiMsg> = {
ready: ReadyCallback<AiMsg>;
preDestroy: PreDestroyCallback<AiMsg>;
messageSent: MessageSentCallback;
messageStreamStarted: MessageStreamStartedCallback;
messageReceived: MessageReceivedCallback<AiMsg>;
messageRendered: MessageRenderedCallback<AiMsg>;
serverComponentStreamStarted: ServerComponentStreamStartedCallback;
serverComponentRendered: ServerComponentRenderedCallback;
error: ErrorCallback;
};
type EventName = keyof EventsMap<unknown>;
type EventCallback<AiMsg = string> = EventsMap<AiMsg>[EventName];
type EventsConfig<AiMsg = string> = Partial<EventsMap<AiMsg>>;
/**
* The status of the AiChat component.
* - `idle`: The component has not been mounted yet.
* - `mounted`: The component is currently mounted and active. It can be visible or hidden.
* - `unmounted`: The component has been unmounted and destroyed and cannot be used anymore.
*/
type AiChatStatus = 'idle' | 'mounted' | 'unmounted';
/**
* The main interface representing AiChat component.
* It provides methods to instantiate, mount, and unmount the component, and listen to its events.
*/
interface IAiChat<AiMsg> {
/**
* Hides the chat component.
* This does not unmount the component. It will only hide the chat component from the view.
*/
hide(): void;
/**
* Mounts the chat component to the given root element.
*
* @param {HTMLElement} rootElement
*/
mount(rootElement: HTMLElement): void;
/**
* Adds an event listener to the chat component.
* The callback will be called when the event is emitted, with the expected event details.
*
* @param {EventName} event The name of the event to listen to.
* @param {EventsMap[EventName]} callback The callback to be called, that should match the event type.
* @returns {IAiChat}
*/
on(event: EventName, callback: EventsMap<AiMsg>[EventName]): IAiChat<AiMsg>;
/**
* Removes all event listeners from the chat component for a specific event.
*
* @param {EventName} event
*/
removeAllEventListeners(event: EventName): void;
/**
* Removes the given event listener for the specified event.
*
* @param {EventName} event The name of the event to remove the listener from.
* @param {EventsMap[EventName]} callback The callback to be removed.
*/
removeEventListener(event: EventName, callback: EventCallback<AiMsg>): void;
/**
* Shows the chat component.
* This method expects the chat component to be mounted.
*/
show(): void;
/**
* Returns true if the chat component is mounted.
*/
get status(): AiChatStatus;
/**
* Unmounts the chat component.
* This will remove the chat component from the view and clean up its resources.
* After unmounting, the chat component cannot be mounted again as all its resources, options, event listeners, and
* adapters will be removed. You should create a new chat component if you want to use it again.
*/
unmount(): void;
/**
* Updates the properties of the chat component. This method expects the chat component to be mounted.
* The properties will be updated and the relevant parts of the chat component will be re-rendered.
*
* @param {UpdatableAiChatProps} props The properties to be updated.
*/
updateProps(props: UpdatableAiChatProps<AiMsg>): void;
/**
* Enabled providing an adapter to the chat component.
* The adapter will be used to send and receive messages from the chat backend.
* This method should be called before mounting the chat component, and it should be called only once.
*
* @param {adapter: ChatAdapter | StandardChatAdapter | ChatAdapterBuilder} adapter The builder for the chat
* adapter.
*/
withAdapter(adapter: ChatAdapter<AiMsg> | StandardChatAdapter<AiMsg> | ChatAdapterBuilder<AiMsg>): IAiChat<AiMsg>;
/**
* Enables providing a class name to the chat component.
* The class name will be added to the root element of the chat component.
* This method should be called before mounting the chat component, and it should be called only once.
*
* @param {string} className The class name to be added to the chat component.
*/
withClassName(className: string): IAiChat<AiMsg>;
/**
* Enables providing composer options to the chat component.
* This method can be called before mounting the chat component, and it can be called only once.
*
* @param {ComposerOptions} composerOptions The composer options to be used.
*/
withComposerOptions(composerOptions: ComposerOptions): IAiChat<AiMsg>;
/**
* The conversation options will be used to configure the conversation behavior and display.
* This method can be called before mounting the chat component, and it can be called only once.
*
* @param {ConversationOptions} conversationOptions The conversation options to be used.
*/
withConversationOptions(conversationOptions: ConversationOptions): IAiChat<AiMsg>;
/**
* Enables providing display options to the chat component. The display options will be used to configure the
* layout of the chat component. When no display options are provided, the default display options will be used.
* This method can be called before mounting the chat component, and it can be called only once.
*
* @param {DisplayOptions} displayOptions The display options to be used.
*/
withDisplayOptions(displayOptions: DisplayOptions): IAiChat<AiMsg>;
/**
* Enables providing an initial conversation to the chat component.
* The initial conversation will be used to populate the chat component with a conversation history.
* This method can be called before mounting the chat component, and it can be called only once.
*
* @param {ChatItem[]} initialConversation
* @returns {IAiChat}
*/
withInitialConversation(initialConversation: ChatItem<AiMsg>[]): IAiChat<AiMsg>;
/**
* Enables providing message options to the chat component.
* The message options will be used to configure the behavior and the
* display of the messages inside the chat component.
*
* @param {MessageOptions<AiMsg>} messageOptions
* @returns {IAiChat<AiMsg>}
*/
withMessageOptions(messageOptions: MessageOptions<AiMsg>): IAiChat<AiMsg>;
/**
* Enables providing persona options to the chat component. The persona options will be used to configure
* the assistant and user personas in the chat component.
* This method can be called before mounting the chat component, and it can be called only once.
*
* @param {PersonaOptions} personaOptions The persona options to be used.
*/
withPersonaOptions(personaOptions: PersonaOptions): IAiChat<AiMsg>;
}
declare class AiChat<AiMsg = string> implements IAiChat<AiMsg> {
protected theAdapter: ChatAdapter<AiMsg> | StandardChatAdapter<AiMsg> | null;
protected theAdapterBuilder: ChatAdapterBuilder<AiMsg> | null;
protected theAdapterType: 'builder' | 'instance' | null;
protected theClassName: string | null;
protected theComposerOptions: ComposerOptions | null;
protected theConversationOptions: ConversationOptions | null;
protected theDisplayOptions: DisplayOptions | null;
protected theInitialConversation: ChatItem<AiMsg>[] | null;
protected theMessageOptions: MessageOptions<AiMsg> | null;
protected thePersonasOptions: PersonaOptions | null;
private aiChatStatus;
private controller;
private unregisteredEventListeners;
get status(): AiChatStatus;
private get isIdle();
hide(): void;
mount(rootElement: HTMLElement): void;
on(event: EventName, callback: EventsMap<AiMsg>[EventName]): this;
removeAllEventListeners(event: EventName): void;
removeEventListener(event: EventName, callback: EventCallback<AiMsg>): void;
show(): void;
unmount(): void;
updateProps(props: UpdatableAiChatProps<AiMsg>): void;
withAdapter(adapter: ChatAdapter<AiMsg> | StandardChatAdapter<AiMsg> | ChatAdapterBuilder<AiMsg>): this;
withClassName(className: string): this;
withComposerOptions(composerOptions: ComposerOptions): this;
withConversationOptions(conversationOptions: ConversationOptions): this;
withDisplayOptions(displayOptions: DisplayOptions): this;
withInitialConversation(initialConversation: ChatItem<AiMsg>[]): this;
withMessageOptions(messageOptions: MessageOptions<AiMsg>): this;
withPersonaOptions(personaOptions: PersonaOptions): this;
private clearEventListeners;
}
interface IObserver<DataType> {
complete?(): void;
error?(error: Error): void;
next(value: DataType): void;
}
declare class Observable<DataType> {
private buffer;
private errorReceived;
private isCompleted;
private readonly isReplayObservable;
private subscribers;
constructor({ replay }?: {
replay?: boolean;
});
complete(): void;
error(error: Error): void;
next(value: DataType): void;
reset(): void;
subscribe(observer: IObserver<DataType>): {
unsubscribe: () => void;
};
unsubscribe(observer: IObserver<DataType>): void;
private sendBufferToObserver;
}
type OutputFormat = 'text' | 'audio' | 'markdown' | 'html' | 'image' | 'video' | 'file';
type InputFormat = 'text';
type AdapterEncodeFunction<OutboundPayload> = (input: string) => Promise<OutboundPayload>;
type AdapterDecodeFunction<InboundPayload> = <AiMsg>(output: InboundPayload) => Promise<AiMsg | undefined>;
/**
* This type represents the information that the AiChat needs to know about an adapter.
* It is used to determine which adapters are available and what capabilities they have.
*/
type StandardAdapterInfo = Readonly<{
id: string;
capabilities: Readonly<{
chat: boolean;
fileUpload: boolean;
textToSpeech: boolean;
speechToText: boolean;
}>;
}>;
/**
* Additional data sent to the adapter when a message is sent.
*/
type ChatAdapterExtras<AiMsg = string> = {
/**
* This attribute contains the properties used with the AiChat component.
*/
aiChatProps: AiChatPropsInEvents<AiMsg>;
/**
* This attribute contains the conversation history.
* It's only included if the `conversationOptions.historyPayloadSize` is set to a positive number or 'all'.
*/
conversationHistory?: ChatItem$1<AiMsg>[];
/**
* This attribute contains the unique identifier of the context instance.
* It's only included if a context instance is used with the AiChat component.
* This can be used to send the context ID to the API and get a response that is specific to the context instance.
*/
contextId?: string;
/**
* This contains the headers that implementers can use to send additional data such as authentication headers.
*/
headers?: Record<string, string>;
};
/**
* This type represents the result of an assist request.
*
* If the request was successful, the `success` property will be `true` and the `response` property will contain the
* text response to be displayed to the user. In addition, when the `task` property is present, it will contain the
* details of the task to be executed by the client.
*
* If the request was not successful, the `success` property will be `false` and the `error` property will contain the
* error message to be displayed to the user.
*/
type AssistResult$1 = {
success: true;
response: string;
task?: {
id: string;
parameters: string[];
};
} | {
success: false;
error: string;
};
/**
* This interface exposes methods that should be implemented by adapters used when the AiChat is in co-pilot mode.
* The difference between this and the `ChatAdapter` interface is that this adapter can return a task to be executed
* by the client in addition to the text response to be displayed.
*
* Assist adapters can only be used in batch mode, and the response cannot be streamed.
*/
interface AssistAdapter$1 {
/**
* This method should be implemented by any adapter that wants to request data from the API in batch mode.
* It should return a promise that resolves to the response from the API.
* Either this method or `streamText` (or both) should be implemented by any adapter.
*
* @param `string` message
* @param `ChatAdapterExtras` extras
* @returns Promise<string>
*/
assist?: (message: string, extras: ChatAdapterExtras$1<string>) => Promise<AssistResult$1>;
}
/**
* This type represents the result of an assist request.
*
* If the request was successful, the `success` property will be `true` and the `response` property will contain the
* text response to be displayed to the user. In addition, when the `task` property is present, it will contain the
* details of the task to be executed by the client.
*
* If the request was not successful, the `success` property will be `false` and the `error` property will contain the
* error message to be displayed to the user.
*/
type AssistResult = {
success: true;
response: string;
task?: {
id: string;
parameters: string[];
};
} | {
success: false;
error: string;
};
/**
* This interface exposes methods that should be implemented by adapters used when the AiChat is in co-pilot mode.
* The difference between this and the `ChatAdapter` interface is that this adapter can return a task to be executed
* by the client in addition to the text response to be displayed.
*
* Assist adapters can only be used in batch mode, and the response cannot be streamed.
*/
interface AssistAdapter {
/**
* This method should be implemented by any adapter that wants to request data from the API in batch mode.
* It should return a promise that resolves to the response from the API.
* Either this method or `streamText` (or both) should be implemented by any adapter.
*
* @param `string` message
* @param `ChatAdapterExtras` extras
* @returns Promise<string>
*/
assist?: (message: string, extras: ChatAdapterExtras$1<string>) => Promise<AssistResult>;
}
/**
* The base interface for creating a new instance of a StandardChatAdapter.
* Adapter builders can extend this interface to add additional methods for configuration.
*/
interface AssistAdapterBuilder {
/**
* Create a new instance of an AssistAdapter.
*/
create(): AssistAdapter;
}
type StreamParser = (root: HTMLElement, syntaxHighlighter?: HighlighterExtension) => IObserver<string>;
type StandardStreamParserOutput = {
next(value: string): void;
complete(): void;
cancel(): void;
error(error: Error): void;
};
type StandardStreamParser = (root: HTMLElement, options?: {
syntaxHighlighter?: HighlighterExtension;
htmlSanitizer?: SanitizerExtension;
markdownLinkTarget?: 'blank' | 'self';
showCodeBlockCopyButton?: boolean;
skipStreamingAnimation?: boolean;
streamingAnimationSpeed?: number;
waitTimeBeforeStreamCompletion?: number | 'never';
onComplete?: () => void;
}) => StandardStreamParserOutput;
type ContextItemDataType$1 = number | string | boolean | null | ContextObject$1 | ContextItemDataType$1[];
type ContextObject$1 = {
[key: string]: ContextItemDataType$1;
};
type ContextItem$1 = {
value: ContextItemDataType$1;
description: string;
};
type ContextItems$1 = Record<string, ContextItem$1>;
type ContextTask$1 = {
description: string;
paramDescriptions: string[];
};
type ContextTasks$1 = Record<string, ContextTask$1>;
type InitializeContextResult$1 = {
success: true;
contextId: string;
} | {
success: false;
error: string;
};
type DestroyContextResult$1 = {
success: true;
} | {
success: false;
error: string;
};
type FlushContextResult$1 = {
success: true;
} | {
success: false;
error: string;
};
type RunTaskResult$1 = {
success: true;
result?: unknown;
} | {
success: false;
error: string;
};
type ContextActionResult$1 = {
success: true;
} | {
success: false;
error: string;
};
type SetContextResult$1 = {
success: true;
contextId: string;
} | {
success: false;
error: string;
};
type ContextItemDataType = number | string | boolean | null | ContextObject | ContextItemDataType[];
type ContextObject = {
[key: string]: ContextItemDataType;
};
type ContextItem = {
value: ContextItemDataType;
description: string;
};
type ContextItems = Record<string, ContextItem>;
type ContextTask = {
description: string;
paramDescriptions: string[];
};
type ContextTasks = Record<string, ContextTask>;
/**
* This represents a set of extra data that can be sent to the context adapter.
* It can be used by implementations to send additional data such as authentication headers.
*/
type ContextAdapterExtras$1 = {
/**
* This contains the headers that implementers can use to send additional data such as authentication headers.
*/
headers?: Record<string, string>;
};
/**
* The context data adapter is responsible for synchronizing the context data between the frontend application
* and the backend system. In order to build a context-aware chat experience and AI assistants, the context
* adapter should be used.
*
* nlux does not set any restrictions on the context data structure or where and how the data should be stored,
* but it expects the backend system responsible for generating the chat responses to be able to access the
* context data as needed.
*
* The goal of the context this adapter is to facilitate providing the context data to the backend.
* The following methods are expected to be implemented by the context data adapter:
*
* - Set context data: On initial load, the context data should be set to the initial state.
* - Get context data: Data loaded from the backend.
* - Update context data: Called when the context data is updated.
* - Clear context data: When the app is closed or the user logs out, the context data should be cleared.
*/
interface ContextDataAdapter$1 {
/**
* Creates a new context and sets the initial context data when provided.
* On success, the new context ID should be returned.
*
* @param {Object} initialData
* @param {ContextAdapterExtras} extras
* @returns {Promise<SetContextResult>}
*/
create: (initialItems?: ContextItems, extras?: ContextAdapterExtras$1) => Promise<SetContextResult$1>;
/**
* Deletes the context data and any registered tasks for the given context ID, and makes the context ID invalid.
* This method should be used when the context is no longer needed.
*
* @param {string} contextId
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
discard: (contextId: string, extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
/**
* Deletes the data for the given context ID and item IDs.
*
* @param {string} contextId The context ID.
* @param {string[]} itemIds The item IDs to delete.
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
removeItems: (contextId: string, itemIds: string[], extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
/**
* Resets the context data for the given context ID.
* If no new context data is not provided, the context will be emptied.
* If new context data is provided, it will replace the existing context data.
*
* @param {string} contextId
* @param {ContextItems} newData
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
resetItems: (contextId: string, newData?: ContextItems, extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
/**
* Updates data for the given context ID.
*
*
* @param {string} contextId
* @param {string} itemId
* @param {Object} data
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
updateItems: (contextId: string, itemsToUpdate: Partial<ContextItems>, extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
}
/**
* The context tasks adapter is responsible for registering and unregistering tasks that can be triggered by
* the AI assistant. The tasks are front-end specific but can be triggered by backend based on specific user
* prompts in the AI chat. In order to build a context-aware chat experience that can also trigger front-end
* tasks, the context tasks adapter should be used to let the backend know about the tasks that can be triggered.
*
* The following methods are expected to be implemented by the context tasks adapter:
*
* - Register task: When a new screen is loaded, or a specific state is reached, a new task can be registered.
* - Unregister task: When the screen is closed or the state is no longer valid, the task should be unregistered.
*/
interface ContextTasksAdapter$1 {
/**
* Unregisters specific tasks from the given context ID, based on their task IDs.
*
* @param {string} contextId
* @param {string} taskIds[]
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
removeTasks: (contextId: string, taskIds: string[], extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
/**
* Resets the tasks for the given context ID.
* If new tasks are provided, they will replace the existing tasks.
* If no tasks are provided, all the tasks will be emptied.
*
* @param {string} contextId
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
resetTasks: (contextId: string, newTasks?: ContextTasks, extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
/**
* Updates the tasks included in the `tasks` object, for the given context ID.
* Tasks that are not included in the `tasks` object should be left unchanged.
* If you want to remove a task, you should use the `removeTasks` method.
*
* @param {string} contextId
* @param {Partial<ContextTasks>} tasks
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
updateTasks: (contextId: string, tasks: Partial<ContextTasks>, extras?: ContextAdapterExtras$1) => Promise<ContextActionResult$1>;
}
/**
* The context adapter context-aware chat experience and AI assistants.
* This type provides the methods for both context data and tasks that should be implemented by adapters
* in order to synchronize data related to the context between the frontend and the backend.
*
* If your chat experience does not require the execution of tasks, you can use the ContextDataAdapter type instead.
* But if you need the LLM to execute tasks, as well as access the context data, you should use the ContextAdapter type
* to implement both the context data and tasks.
*/
interface ContextAdapter$1 extends ContextDataAdapter$1, ContextTasksAdapter$1 {
}
/**
* This represents a set of extra data that can be sent to the context adapter.
* It can be used by implementations to send additional data such as authentication headers.
*/
type ContextAdapterExtras = {
/**
* This contains the headers that implementers can use to send additional data such as authentication headers.
*/
headers?: Record<string, string>;
};
/**
* The context tasks adapter is responsible for registering and unregistering tasks that can be triggered by
* the AI assistant. The tasks are front-end specific but can be triggered by backend based on specific user
* prompts in the AI chat. In order to build a context-aware chat experience that can also trigger front-end
* tasks, the context tasks adapter should be used to let the backend know about the tasks that can be triggered.
*
* The following methods are expected to be implemented by the context tasks adapter:
*
* - Register task: When a new screen is loaded, or a specific state is reached, a new task can be registered.
* - Unregister task: When the screen is closed or the state is no longer valid, the task should be unregistered.
*/
interface ContextTasksAdapter {
/**
* Unregisters specific tasks from the given context ID, based on their task IDs.
*
* @param {string} contextId
* @param {string} taskIds[]
* @param {ContextAdapterExtras} extras
* @returns {Promise<ContextActionResult>}
*/
removeTasks: (