Skip to main content

use-x-chat

Focus on explaining how to use the useXChat Hook, including custom Provider integration, message management, error handling, multi-conversation management, and more

소스 정보

저장소
modelscope/ms-agent
최근 소스 활동
2026년 9월 8일 10:28
감지된 SKILL.md 언어
영어
스타
4,412
포크
532

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
4 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
use-x-chat
version
2.8.1
description
Focus on explaining how to use the useXChat Hook, including custom Provider integration, message management, error handling, multi-conversation management, and more
# 🎯 Skill Positioning > **Core Positioning**: Use the `useXChat` Hook to build professional AI conversation applications. **Prerequisite**: Already have a custom Chat Provider (refer to [x-chat-provider skill](../x-chat-provider)) ## Table of Contents - [🚀 Quick Start](#-quick-start) - [🧩 Core Concepts](#-core-concepts) - [Data Model](#data-model) - [Configuration Options](#usexchat-configuration-options) - [Return Values](#usexchat-return-values) - [🔧 Core Function Details](#-core-function-details) - [🗂️ Multi-conversation Management](#️-multi-conversation-management) - [📋 Prerequisites and Dependencies](#-prerequisites-and-dependencies) - [🚨 Development Rules](#-development-rules) - [🔗 Reference Resources](#-reference-resources) # 🚀 Quick Start ## 1. Dependency Management - **@ant-design/x-sdk**: 2.2.2+ - **@ant-design/x**: latest version (UI components) ```bash npm install @ant-design/x-sdk@latest @ant-design/x@latest ``` ## 2. Three-step Integration ### Step 1: Prepare Provider Handled by the x-chat-provider skill. Note `XRequest` must pass `manual: true`: ```ts import { MyChatProvider } from './MyChatProvider'; import { XRequest } from '@ant-design/x-sdk'; // ⚠️ manual: true is required const provider = new MyChatProvider({ request: XRequest('https://your-api.com/chat', { manual: true }), }); ``` ### Step 2: Basic Usage ```tsx import { useXChat } from '@ant-design/x-sdk'; const ChatComponent = () => { const { messages, onRequest, isRequesting } = useXChat({ provider, requestPlaceholder: (_, { messages }) => ({ content: 'Thinking...', role: 'assistant', }), requestFallback: (_, { error, messageInfo }) => { if (error.name === 'AbortError') { return { content: messageInfo?.message?.content || 'Reply cancelled', role: 'assistant' }; } return { content: 'Network error, please try again later', role: 'assistant' }; }, }); return ( <div> {messages.map((msg) => ( <div key={msg.id}> {msg.message.role}: {msg.message.content} </div> ))} <button onClick={() => onRequest({ query: 'Hello' })}>Send</button> </div> ); }; ``` ### Step 3: UI Integration > ⚠️ `messages` is `MessageInfo<ChatMessage>[]` and cannot be passed directly to `Bubble.List`. It must be mapped to `{ key, role, content, loading }` format. **`Bubble.List` uses the `role` prop** (not `roles`) to configure role styles. ```tsx import { Bubble, Sender } from '@ant-design/x'; const ChatUI = () => { const { messages, onRequest, isRequesting, abort } = useXChat({ provider }); return ( <div style={{ height: 600 }}> <Bubble.List // ✅ Correct: use role (not roles) role={{ user: { placement: 'end' }, assistant: { placement: 'start' }, }} items={messages.map(({ id, message, status }) => ({ key: id, role: message.role, // matches role config key content: message.content, // message content loading: status === 'loading', // loading animation }))} /> <Sender loading={isRequesting} onSubmit={(content) => onRequest({ query: content })} onCancel={abort} /> </div> ); }; ``` #### When ChatMessage is an object type (not string) When `ChatMessage` is a complex object (e.g., with `content`, `attachments` fields), use `contentRender`: ```tsx <Bubble.List role={{ assistant: { placement: 'start', // contentRender receives content param, which is the message field itself contentRender(content: MyMessage) { return ( <div> <div>{content.content}</div> {content.attachments?.map((a) => ( <FileCard key={a.url} name={a.name} /> ))} </div> ); }, }, user: { placement: 'end', contentRender(content: MyMessage) { return content.content; }, }, }} items={messages.map(({ id, message, status }) => ({ key: id, role: message.role, content: message, // ⚠️ Pass the entire message object; contentRender handles rendering loading: status === 'loading', }))} /> ``` # 🧩 Core Concepts ## Data Model > ⚠️ **Important**: `messages` type is `MessageInfo<ChatMessage>[]`; message content is in `msg.message` ```ts interface MessageInfo<ChatMessage> { id: number | string; // Message unique identifier message: ChatMessage; // Actual message content (your ChatMessage type) status: MessageStatus; // Message status extraInfo?: AnyObject; // Extended info (note: extraInfo, not extra) } type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort'; // local: locally sent user message // loading: AI reply placeholder (corresponds to requestPlaceholder) // updating: AI streaming output in progress // success: AI reply complete // error: request failed // abort: user actively cancelled ``` ## useXChat Configuration Options | Option | Type | Description | | --- | --- | --- | | `provider` | `AbstractChatProvider<ChatMessage, Input, Output>` | **Required**, Provider instance | | `conversationKey` | `string` | Conversation unique identifier, required for multi-conversation | | `defaultMessages` | `DefaultMessageInfo[] \| () => ... \| async () => ...` | Default display messages, supports async loading | | `requestPlaceholder` | `ChatMessage \| (requestParams, { messages }) => ChatMessage` | Placeholder message during request | | `requestFallback` | `ChatMessage \| (requestParams, { error, errorInfo, messages, messageInfo }) => ChatMessage \| Promise<ChatMessage>` | Fallback message on request failure/abort | | `parser` | `(message: ChatMessage) => BubbleMessage \| BubbleMessage[]` | Convert ChatMessage to component-consumable format, supports one-to-many | > `requestFallback`'s `messageInfo` type is `MessageInfo<ChatMessage>`, the message being updated when the request fails. `requestFallback` handles both network errors (`error`) and user abort (`error.name === 'AbortError'`). ## useXChat Return Values | Return Value | Type | Description | | --- | --- | --- | | `messages` | `MessageInfo<ChatMessage>[]` | Message list; must be mapped before passing to `Bubble.List` | | `parsedMessages` | `MessageInfo<ParsedMessage>[]` | Message list after `parser` transform (use this when parser is set) | | `onRequest` | `(params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void` | Add message and trigger request | | `isRequesting` | `boolean` | Whether request is in progress | | `abort` | `() => void` | Abort current request | | `setMessages` | `(messages: Partial<MessageInfo<ChatMessage>>[]) => void` | Directly modify message list, no request triggered | | `setMessage` | `(id: string \| number, info: Partial<MessageInfo<ChatMessage>>) => void` | Modify single message, no request triggered | | `removeMessage` | `(id: string \| number) => boolean` | Delete a message, returns whether deletion was successful | | `onReload` | `(id: string \| number, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void` | Regenerate an AI reply | | `queueRequest` | `(conversationKey: string \| symbol, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void` | Queue request, sent after conversation initializes | | `isDefaultMessagesRequesting` | `boolean` | Whether default messages are async loading | # 🔧 Core Function Details Core functionality reference: [CORE.md](reference/CORE.md) # 🗂️ Multi-conversation Management ### useXConversations Hook `useXConversations` is a conversation list management Hook provided by `@ant-design/x-sdk`, used together with `useXChat` for multi-conversation: ```ts import { useXConversations } from '@ant-design/x-sdk'; import type { ConversationData } from '@ant-design/x-sdk'; const { conversations, // ConversationData[]: conversation list activeConversationKey, // string: currently active conversation key setActiveConversationKey, // (key: string) => void: switch conversation addConversation, // (ConversationData, placement?) => boolean removeConversation, // (key: string) => boolean setConversation, // (key: string, ConversationData) => boolean getConversation, // (key: string) => ConversationData | undefined setConversations, // (list: ConversationData[]) => void getMessages, // (key: string) => MessageInfo[] | undefined (read messages across components) } = useXConversations({ defaultConversations: [ { key: 'conv-1', label: 'Conversation 1' }, { key: 'conv-2', label: 'Conversation 2' }, ], defaultActiveConversationKey: 'conv-1', }); ``` ### Multi-conversation Full Pattern ```tsx import { useXChat, useXConversations } from '@ant-design/x-sdk'; import { OpenAIChatProvider, XRequest } from '@ant-design/x-sdk'; import { Bubble, Conversations, Sender } from '@ant-design/x'; import React, { useEffect, useRef } from 'react'; // ⚠️ Each conversation must have its own Provider instance, otherwise state mixes const providerCache = new Map<string, OpenAIChatProvider>(); function getProvider(key: string): OpenAIChatProvider { if (!providerCache.has(key)) { providerCache.set( key, new OpenAIChatProvider({ request: XRequest(BASE_URL, { manual: true, params: { model: 'gpt-4o', stream: true } }), }), ); } return providerCache.get(key)!; } const App = () => { const senderRef = useRef<any>(null); const { conversations, activeConversationKey, setActiveConversationKey, addConversation } = useXConversations({ defaultConversations: [{ key: 'conv-1', label: 'New Conversation' }], defaultActiveConversationKey: 'conv-1', }); const { messages, onRequest, isRequesting, abort, queueRequest } = useXChat({ provider: getProvider(activeConversationKey), conversationKey: activeConversationKey, // Async load default messages defaultMessages: async ({ conversationKey }) => { // Load history from server based on conversationKey return []; }, requestFallback: (_, { error, messageInfo }) => { if (error.name === 'AbortError') { return { content: messageInfo?.message?.content || 'Cancelled', role: 'assistant' }; } return { content: 'Request failed', role: 'assistant' }; }, }); // Clear input on conversation switch useEffect(() => { senderRef.current?.clear?.(); }, [activeConversationKey]); const handleNewConversation = () => { const newKey = `conv-${Date.now()}`; addConversation({ key: newKey, label: `New Conversation ${conversations.length + 1}` }); setActiveConversationKey(newKey); }; return ( <div style={{ display: 'flex', height: '100vh' }}> <Conversations items={conversations} activeKey={activeConversationKey} onActiveChange={setActiveConversationKey} creation={{ onClick: handleNewConversation }} /> <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}> <Bubble.List
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기