graph TD
A[Start] --> B{Use standard OpenAI/DeepSeek API?}
B -->|Yes| C[Use built-in Provider]
B -->|No| D{Raw data format as message?}
D -->|Yes| E[Use DefaultChatProvider]
D -->|No| F[Custom Provider]
C --> G[OpenAIChatProvider / DeepSeekChatProvider]
E --> H[Pass-through, no conversion needed]
F --> I[Four-step custom Provider]
🏭 Built-in Provider Overview
Provider Type
Applicable Scenario
Import
OpenAIChatProvider
Standard OpenAI API format
import { OpenAIChatProvider } from '@ant-design/x-sdk'
DeepSeekChatProvider
Standard DeepSeek API format
import { DeepSeekChatProvider } from '@ant-design/x-sdk'
DefaultChatProvider
Pass-through raw response, no format conversion
import { DefaultChatProvider } from '@ant-design/x-sdk'
// XModelMessage is the standard OpenAI message format// Used for OpenAIChatProvider / DeepSeekChatProvider ChatMessage genericconstuserMessage: XModelMessage = { role: 'user', content: 'Hello' };
constsystemMessage: XModelMessage = { role: 'system', content: 'You are an assistant' };
constdeveloperMessage: XModelMessage = { role: 'developer', content: 'System prompt' };
SSEOutput and SSEFields
// SSEOutput is the type for raw SSE stream data// { data?: string; event?: string; id?: string; retry?: number }// DeepSeekChatProvider uses Partial<Record<SSEFields, XModelResponse>>import { DeepSeekChatProvider, XRequest } from'@ant-design/x-sdk';
importtype { SSEFields, XModelParams, XModelResponse } from'@ant-design/x-sdk';
const provider = newDeepSeekChatProvider({
request: XRequest<XModelParams, Partial<Record<SSEFields, XModelResponse>>>(
'https://api.deepseek.com/v1/chat/completions',
{
manual: true,
params: { model: 'deepseek-chat', stream: true },
},
),
});
⚙️ XRequest Advanced Configuration
callbacks
callbacks allows monitoring request events at the Provider level. The third parameter in callbacks is the MessageInfo processed by transformMessage:
const provider = newOpenAIChatProvider({
request: XRequest<XModelParams, XModelResponse, XModelMessage>(BASE_URL, {
manual: true,
callbacks: {
// onUpdate: triggered on each streaming chunk arrival// chunk: current chunk; responseHeaders: response headers; message: current MessageInfoonUpdate: (chunk, responseHeaders, message) => {
console.log('Stream update:', message?.message?.content);
},
// onSuccess: triggered when all chunks are received// chunks: all chunks array; message: final MessageInfoonSuccess: (chunks, responseHeaders, message) => {
console.log('Request complete:', message?.message?.content);
// Good place for analytics, logging, etc.
},
// onError: triggered on request failure (including AbortError)// error: error object; errorInfo: extra error info; message: MessageInfo at failureonError: (error, errorInfo, responseHeaders, message) => {
console.error('Request failed:', error.message);
},
},
params: { model: 'gpt-4o', stream: true },
}),
});
⚠️ callbacks and useXChat's requestFallback do not conflict — both execute. callbacks is better for logging/reporting; requestFallback controls UI display.
retryInterval Retry
const request = XRequest('https://your-api.com/chat', {
manual: true,
// Retry interval after failure (ms)retryInterval: 3000,
// Max retry count (unlimited if not set)retryTimes: 3,
// onError can also return a number to dynamically set retry intervalcallbacks: {
onError: (error) => {
if (error.name === 'AbortError') return; // Don't retry on user cancelreturn5000; // Return number = retry after 5s (higher priority than retryInterval)
},
},
});
transformStream Custom Stream
Use when the server returns a non-standard SSE stream format:
const request = XRequest('https://your-api.com/chat', {
manual: true,
// Fixed TransformStreamtransformStream: newTransformStream({
transform(chunk, controller) {
controller.enqueue(JSON.parse(chunk));
},
}),
// Or decide dynamically based on URL and response headerstransformStream: (baseURL, responseHeaders) => {
if (responseHeaders.get('x-stream-type') === 'ndjson') {
returnnewTransformStream({/* ... */});
}
returnundefined; // Use default SSE parsing
},
});
// ❌ WrongtransformMessage(info) {
return { content: '...', status: 'error' }; // ❌ status is managed by the framework
}
// ✅ CorrecttransformMessage(info) {
return { content: '...' }; // ✅
}
⚠️ Provider instantiation notes
// ✅ In React components, use useState to ensure only created onceconst [provider] = React.useState(
newMyChatProvider({
request: XRequest(URL, { manual: true }),
}),
);
// ❌ Don't create directly in render function (creates new instance on every render)// const provider = new MyChatProvider(...); // inside component body causes issues
⚡ Quick Checklist
Before creating Provider:
Have interface docs and response format
Confirmed whether custom is needed (or if built-in Provider suffices)
Defined Input, Output, ChatMessage types
After completion:
Only implemented the three required methods
transformParams includes second parameter options
transformMessage return value has no status field
XRequest configured with manual: true
Absolutely no request method implemented
Provider wrapped with useState in React component
Type check passes (tsc --noEmit)
🚨 Development Rules
If the user does not explicitly need test cases, do not add test files
After completion, must check types: Run tsc --noEmit to ensure no type errors
Keep code clean: Remove all unused variables and imports