跳到正文
cccskills
免费在 GitHub 公开

use-x-chat

Implement AI chat behavior with useXChat, a React function for managing chat state. Connect Providers that handle API communication, manage messages and errors, regenerate or cancel replies, and support multiple conversations with separate state.

中文简介正在准备中。当前显示英语简介。

原文查看原文说明

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

集成工具OpenAI
查看安装方法

适用场景

  • Connect chat messages to Bubble.List and Sender
  • Handle network errors and canceled replies
  • Add message deletion and reply regeneration
  • Switch conversations and send after history finishes loading

包含的文件(4)

  • SKILL.md14.6 KB
  • reference/API.md5.2 KB
  • reference/CORE.md8.4 KB
  • reference/EXAMPLES.md12.1 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

🎯 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)

Table of Contents

🚀 Quick Start

1. Dependency Management

  • @ant-design/x-sdk: 2.2.2+
  • @ant-design/x: latest version (UI components)
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:

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

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.

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:

<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

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

OptionTypeDescription
providerAbstractChatProvider<ChatMessage, Input, Output>Required, Provider instance
conversationKeystringConversation unique identifier, required for multi-conversation
defaultMessagesDefaultMessageInfo[] | () => ... | async () => ...Default display messages, supports async loading
requestPlaceholderChatMessage | (requestParams, { messages }) => ChatMessagePlaceholder message during request
requestFallbackChatMessage | (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 ValueTypeDescription
messagesMessageInfo<ChatMessage>[]Message list; must be mapped before passing to Bubble.List
parsedMessagesMessageInfo<ParsedMessage>[]Message list after parser transform (use this when parser is set)
onRequest(params: Partial<Input>, opts?: { extraInfo: AnyObject }) => voidAdd message and trigger request
isRequestingbooleanWhether request is in progress
abort() => voidAbort current request
setMessages(messages: Partial<MessageInfo<ChatMessage>>[]) => voidDirectly modify message list, no request triggered
setMessage(id: string | number, info: Partial<MessageInfo<ChatMessage>>) => voidModify single message, no request triggered
removeMessage(id: string | number) => booleanDelete a message, returns whether deletion was successful
onReload(id: string | number, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => voidRegenerate an AI reply
queueRequest(conversationKey: string | symbol, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => voidQueue request, sent after conversation initializes
isDefaultMessagesRequestingbooleanWhether default messages are async loading

🔧 Core Function Details

Core functionality 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:

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

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
          role={{ assistant: { placement: 'start' }, user: { placement: 'end' } }}
          items={messages.map(({ id, message, status }) => ({
            key: id,
            role: message.role,
            content: message.content,
            loading: status === 'loading',
          }))}
        />
        <Sender
          ref={senderRef}
          loading={isRequesting}
          onCancel={abort}
          onSubmit={(val) => {
            onRequest({ messages: [{ role: 'user', content: val }] });
          }}
        />
      </div>
    </div>
  );
};

queueRequest: Delayed Send After Conversation Switch

// Scenario: user switches to a new conversation and triggers an initial message simultaneously
// queueRequest waits for defaultMessages async loading to complete, then sends the request

const handleNewConversationWithFirstMessage = () => {
  const newKey = `conv-${Date.now()}`;
  addConversation({ key: newKey, label: 'New Conversation' });
  setActiveConversationKey(newKey);

  // Queue the message; sent automatically after newKey conversation's defaultMessages finish loading
  queueRequest(newKey, {
    messages: [{ role: 'user', content: 'Hello! Please introduce yourself.' }],
  });
};

📋 Prerequisites and Dependencies

Usage ScenarioRequired Skill/ProviderOrder
Private API Adaptationx-chat-provider → use-x-chatCreate Provider first
Standard APIBuilt-in Provider + use-x-chatDirect use
Multi-conversationProvider factory + useXConversations + useXChatUse together

🚨 Development Rules

Before using use-x-chat, confirm:

  • Has Provider (custom or built-in Provider)
  • Provider's XRequest is configured with manual: true
  • Understands MessageInfo data structure (message content is in msg.message)
  • Bubble.List uses role prop (not roles)
  • Multi-conversation scenario: each conversation has its own Provider instance

Test Case Rules

  • If the user does not explicitly need test cases, do not add test files

Code Quality Rules

  • After completion, must check types: Run tsc --noEmit to ensure no type errors
  • Keep code clean: Remove all unused variables and imports

🔗 Reference Resources

📚 Core Reference Documentation

🌐 SDK Official Documentation

💻 Example Code

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Implement AI chat behavior with useXChat, a React function for managing chat state. Connect Providers that handle API communication, manage messages and errors, regenerate or cancel replies, and support multiple conversations with separate state.

中文简介正在准备中。当前显示英语简介。

  • Connect chat messages to Bubble.List and Sender
  • Handle network errors and canceled replies
  • Add message deletion and reply regeneration
ant-design/x48172026年10月12日 更新

x-card

免费

Build interactive React cards and forms from JSON commands sent by an AI agent. Using @ant-design/x-card and A2UI, a protocol for describing interfaces, this skill covers data binding, user actions, custom components, and progressive rendering.

中文简介正在准备中。当前显示英语简介。

  • Display interactive cards inside AI chat responses
  • Build forms driven by agent commands
  • Render an interface progressively as commands arrive
ant-design/x48172026年10月12日 更新

x-card

免费

Build interactive cards and forms in React from an AI agent’s structured JSON commands. The skill guides component registration, connections between data and interface elements, user action handling, and progressive rendering with @ant-design/x-card.

中文简介正在准备中。当前显示英语简介。

  • Build an interactive form controlled by an AI agent
  • Update cards progressively as agent commands arrive
  • Connect form inputs to data and return user actions
ant-design/x48172026年10月12日 更新

Connect streaming APIs to Ant Design X by implementing a Chat Provider, an adapter for request and message formats. Choose built-in providers where suitable, transform custom responses, and configure authentication, retries, and stream parsing.

中文简介正在准备中。当前显示英语简介。

  • Connect a private streaming API to Ant Design X
  • Choose a provider for OpenAI or DeepSeek
  • Convert responses containing multiple fields
ant-design/x48172026年10月12日 更新

Adapt a streaming API to Ant Design X by selecting or implementing a Chat Provider, the layer that converts requests and responses into chat messages. Includes custom formats, incremental message assembly, and nonstandard stream handling.

中文简介正在准备中。当前显示英语简介。

  • Choose a built-in provider for OpenAI or DeepSeek
  • Connect a private SSE API to Ant Design X
  • Convert responses with multiple fields into chat messages
ant-design/x48172026年10月12日 更新

Build AI chat interfaces with @ant-design/x, a React library of interface components. Get guidance on choosing and combining message bubbles, input boxes, conversation lists, attachments, and source citations, with API references and common implementation pitfalls.

中文简介正在准备中。当前显示英语简介。

  • Build a chat page with message bubbles and an input box
  • Add a conversation list and switching controls
  • Display attachments and source citations
ant-design/x48172026年10月12日 更新

查看 ant-design 的全部技能

报告此技能的问题