Participate in the WeaveFox "AI Artist" contest to win SEE Conf tickets and thousands of prizes

logoAnt Design X

DesignDevelopmentComponentsX MarkdownX SDKPlayground
  • Introduction
  • Data Flow
    • useXChat
    • useXConversations
  • Chat Provider
    • Chat Provider
    • OpenAIChatProvider
    • DeepSeekChatProvider
    • Custom Chat Provider
  • Utilities
    • XRequestRequest
    • XStreamStream

Custom Chat Provider

When the built-in Chat Provider doesn't meet your needs, you can implement the abstract class AbstractChatProvider (which only contains three abstract methods) to convert data from different model providers or Agentic services into a unified format that useXChat can consume, enabling seamless integration and switching between different models and agents.

AbstractChatProvider

AbstractChatProvider is an abstract class used to define the interface for Chat Provider. When you need to use a custom data service, you can inherit from AbstractChatProvider and implement its methods. You can refer to the Playground - Toolbox for examples.

ts
type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error';
interface ChatProviderConfig<Input, Output> {
request: XRequestClass<Input, Output> | (() => XRequestClass<Input, Output>);
}
interface TransformMessage<ChatMessage, Output> {
originMessage?: ChatMessage;
chunk: Output;
chunks: Output[];
status: MessageStatus;
}
abstract class AbstractChatProvider<ChatMessage, Input, Output> {
constructor(config: ChatProviderConfig<Input, Output>): void;
/**
* Transform parameters passed to onRequest. You can merge or additionally process them with the params in the request configuration when instantiating the Provider
* @param requestParams Request parameters
* @param options Request configuration, from the request configuration when instantiating the Provider
*/
abstract transformParams(
requestParams: Partial<Input>,
options: XRequestOptions<Input, Output>,
): Input;
/**
* Convert parameters passed to onRequest into a local (user-sent) ChatMessage for message rendering
* @param requestParams Parameters passed to onRequest
*/
abstract transformLocalMessage(requestParams: Partial<Input>): ChatMessage;
/**
* Can transform messages when updating returned data, and will also update messages
* @param info
*/
abstract transformMessage(info: TransformMessage<ChatMessage, Output>): ChatMessage;
}

Complete Process for Custom Provider

Below is a custom Provider example showing how to customize a Chat Provider. Detailed explanations follow the code example.

Complete Example

ts
// Type definitions
type CustomInput = {
query: string;
};
type CustomOutput = {
data: string;
};
type CustomMessage = {
content: string;
role: 'user' | 'assistant';
};
class CustomProvider<
ChatMessage extends CustomMessage = CustomMessage,
Input extends CustomInput = CustomInput,
Output extends CustomOutput = CustomOutput,
> extends AbstractChatProvider<ChatMessage, Input, Output> {
transformParams(requestParams: Partial<Input>, options: XRequestOptions<Input, Output>): Input {
if (typeof requestParams !== 'object') {
throw new Error('requestParams must be an object');
}
return {
...(options?.params || {}),
...(requestParams || {}),
} as Input;
}
transformLocalMessage(requestParams: Partial<Input>): ChatMessage {
return {
content: requestParams.query,
role: 'user',
} as unknown as ChatMessage;
}
transformMessage(info: TransformMessage<ChatMessage, Output>): ChatMessage {
const { originMessage, chunk } = info || {};
if (!chunk || !chunk?.data || (chunk?.data && chunk?.data?.includes('[DONE]'))) {
return {
content: originMessage?.content || '',
role: 'assistant',
} as ChatMessage;
}
const chunkJson = JSON.parse(chunk.data);
const content = originMessage?.content || '';
return {
content: `${content || ''}${chunkJson.data || ''}`,
role: 'assistant',
} as ChatMessage;
}
}

Detailed Explanation

  1. The Agentic service streaming interface https://xxx.agent.com/api/stream.

Request parameters:

json
{
"query": "Help me summarize today's tech news"
}

Response data:

json
id:1
data: "Okay,"
id:2
data: "I'll help you"
id:3
data: "summarize today's"
id:4
data: "tech news,"
  1. Based on the interface, we can define the CustomInput and CustomOutput types.

CustomInput type:

ts
{
query: string;
}

Since we only need to convert the data string to JSON and concatenate the internal data field, the CustomOutput type is:

ts
{
data: string;
}
  1. We expect the messages data generated by useXChat to be directly consumable by Bubble.List, so we can define CustomMessage as:
ts
{
content: string;
role: 'user' | 'assistant';
}
  1. Then inherit from AbstractChatProvider and implement its methods to get CustomProvider. AbstractChatProvider only requires implementing three methods.
  • transformParams is used to transform parameters passed to onRequest. You can merge or additionally process them with the params in the request configuration when instantiating the Provider.
  • transformLocalMessage converts parameters passed to onRequest into a local (user-sent) ChatMessage for user message rendering, and will also update messages for message list rendering.
  • transformMessage can transform data into ChatMessage data type when updating returned data, and will also update messages for message list rendering.
  1. Finally, we can instantiate CustomProvider and pass it to useXChat to complete the custom Provider usage.
tsx
const [provider] = React.useState(
new CustomProvider({
request: XRequest<CustomInput, CustomOutput>('https://xxx.agent.com/api/stream', {
manual: true,
}),
}),
);
const { onRequest, messages, setMessages, setMessage, isRequesting, abort, onReload } = useXChat({
provider,
});
  1. Send request:
tsx
onRequest({
query: "Help me summarize today's tech news",
});

Usage Example

Contributing Chat Provider

We welcome community contributions for new Chat Providers! Please follow these specifications for Chat Provider development.

Contribution Guide

This guide will help you contribute to Ant Design. Please take a few minutes to read this contribution guide before submitting an issue or pull request.

Contribution Standards

Chat Providers should follow these specifications:

  • Chat Providers should be included in the packages/x-sdk/src/chat-providers directory.
  • Chat Provider types should be included in the packages/x-sdk/src/chat-providers/type directory.

Naming Conventions

Chat Provider theme files should follow these naming rules:

  • Chat Provider theme files should be named in camelCase format as [Vendor][Type][Version].ts.
  • For specific models, they can be directly named in camelCase format as [Vendor][ModelName].ts.
Basic

Work with X components using custom provider to display messages and historical messages.

CodeSandbox Icon
codepen icon
External Link Icon
expand codeexpand code

Custom Provider Example

This is an example using a custom provider, demonstrating how to extend AbstractChatProvider to implement custom data processing logic.

This is a historical response message, please send a new message.
This is a historical message