
Use X Chat
- 5 installs
- 71 repo stars
- Updated August 4, 2026
- antdv-next/x
use-x-chat is a Claude Code skill for using the useXChat Vue 3 composable from @antdv-next/x-sdk to manage AI chat message state, requests, and errors.
About
This skill explains how to use the useXChat Vue 3 composable from @antdv-next/x-sdk to build AI chat applications. A developer uses it to manage message state, control requests, and handle errors after wiring a custom Chat Provider. It shows three-step integration from provider setup to Bubble.List and Sender UI, and warns that messages is a Ref accessed via .value.
- Explains the useXChat Vue 3 composable for chat state and message management
- Covers custom Provider integration, request control, and error handling
- Notes messages is a Ref requiring .value access
Use X Chat by the numbers
- 5 all-time installs (skills.sh)
- Ranked #1,791 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
use-x-chat capabilities & compatibility
- Capabilities
- chat state · ai chat ui · request control
- Use cases
- frontend
What use-x-chat says it does
Use the `useXChat` Hook to build professional AI conversation applications
`messages` type is `Ref<MessageInfo<MessageType>[]>`, not direct `MessageType`. Access via `messages.value`.
npx skills add https://github.com/antdv-next/x --skill use-x-chatAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| repo stars | ★ 71 |
| Last updated | August 4, 2026 |
| Repository | antdv-next/x ↗ |
What it does
Manage Vue 3 AI chat state, requests, and errors with the useXChat composable.
Who is it for?
Managing chat state and message flow in a Vue 3 AI chat app with @antdv-next/x
Skip if: Adapting an API shape or rendering markdown, which other x-* skills cover
When should I use this skill?
You have a custom Chat Provider and need to manage chat state in Vue 3
What you get
A Vue chat UI driven by useXChat with placeholder and fallback handling
- Vue chat component using useXChat
By the numbers
- Three-step integration from provider to UI
Files
🎯 Skill Positioning
Core Positioning: Use the useXChat Hook to build professional AI conversation applications Prerequisites: Already have a custom Chat Provider (refer to x-chat-provider skill)Table of Contents
- 🚀 Quick Start
- Dependency Management
- Three-step Integration
- 🧩 Core Concepts
- Technology Stack Architecture
- Data Model
- 🔧 Core Function Details
- Message Management
- Request Control
- Error Handling
- Complete Example Project
- 📋 Prerequisites and Dependencies
- 🚨 Development Rules
- 🔗 Reference Resources
- 📚 Core Reference Documentation
- 🌐 SDK Official Documentation
- 💻 Example Code
🚀 Quick Start
1. Dependency Management
🎯 Automatic Dependency Handling
📋 System Requirements
- @antdv-next/x-sdk: latest version (automatically installed)
- @antdv-next/x: latest version (UI components, automatically installed)
⚠️ Version Issue Auto-fix
If version mismatch is detected, the skill will automatically:
- ✅ Prompt current version status
- ✅ Provide fix suggestions
- ✅ Use relative paths to ensure compatibility
🎯 Built-in Version Check
The use-x-chat skill has built-in version checking functionality, automatically checking version compatibility on startup:
🔍 Auto-check Function The skill will automatically check if the @antdv-next/x-sdk version meets requirements on startup:
📋 Check Contents:
- ✅ Currently installed version
- ✅ Whether it meets minimum requirements
- ✅ Automatically provide fix suggestions
- ✅ Friendly error prompts
🛠️ Version Issue Fix If version mismatch is detected, the skill will provide specific fix commands:
# Auto-prompted fix commands
npm install @antdv-next/x-sdk@latest2. Three-step Integration
Step 1: Prepare Provider
This part is handled by the x-chat-provider skill
import { MyChatProvider } from "./MyChatProvider";
import { XRequest } from "@antdv-next/x-sdk";
// Recommended to use XRequest as the default request method
const provider = new MyChatProvider({
// Default use XRequest, no need for custom fetch
request: XRequest("https://your-api.com/chat"),
// When requestPlaceholder is set, placeholder message will be displayed before request starts
requestPlaceholder: {
content: "Thinking...",
role: "assistant",
timestamp: Date.now(),
},
// When requestFallback is set, fallback message will be displayed when request fails
requestFallback: (_, { error, errorInfo, messageInfo }) => {
if (error.name === "AbortError") {
return {
content: messageInfo?.message?.content || "Reply cancelled",
role: "assistant" as const,
timestamp: Date.now(),
};
}
return {
content:
errorInfo?.error?.message || "Network error, please try again later",
role: "assistant" as const,
timestamp: Date.now(),
};
},
});Step 2: Basic Usage
import { defineComponent } from "vue";
import { useXChat } from "@antdv-next/x-sdk";
const ChatComponent = defineComponent(() => {
const { messages, onRequest, isRequesting } = useXChat({ provider });
return () => (
<div>
{messages.value.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
import { defineComponent } from "vue";
import { Bubble, Sender } from "@antdv-next/x";
import { useXChat } from "@antdv-next/x-sdk";
const ChatUI = defineComponent(() => {
const { messages, onRequest, isRequesting, abort } = useXChat({ provider });
return () => (
<div style={{ height: "600px" }}>
<Bubble.List items={messages.value} />
<Sender
loading={isRequesting.value}
onSubmit={content => onRequest({ query: content })}
onCancel={abort}
/>
</div>
);
});🧩 Core Concepts
Technology Stack Architecture
graph TD
A[useXChat Hook] --> B[Chat Provider]
B --> C[XRequest]
A --> D[Antdv Next X UI]
D --> E[Bubble Component]
D --> F[Sender Component]Data Model
⚠️ Important Reminder:messagestype isRef<MessageInfo<MessageType>[]>, not directMessageType. Access viamessages.value.
interface MessageInfo<Message> {
id: number | string; // Message unique identifier
message: Message; // Actual message content
status: MessageStatus; // Sending status
extraInfo?: AnyObject; // Extended information
}
// Message status enum
type MessageStatus =
| "local"
| "loading"
| "updating"
| "success"
| "error"
| "abort";🔧 Core Function Details
💡 Tip: API may update with versions, it is recommended to check official documentation for the latest information
Core functionality reference content CORE.md
📋 Prerequisites and Dependencies
⚠️ Important Dependencies
use-x-chat must depend on one of the following skills:
| Dependency Type | Skill | Description | Required |
|---|---|---|---|
| Core Dependency | x-chat-provider | Provides custom Provider instance, default uses XRequest, must be used with use-x-chat | Required |
| Or | Built-in Provider | OpenAI/DeepSeek and other built-in Providers, default uses XRequest | Required |
| Recommended Dependency | x-request | Configure request parameters and authentication, as the default request method | Recommended |
🎯 Usage Scenario Comparison Table
| Usage Scenario | Required Skill Combination | Usage Order |
|---|---|---|
| Private API Adaptation | x-chat-provider → use-x-chat | Create Provider first, then use |
| Standard API Usage | use-x-chat (built-in Provider) | Direct use |
| Authentication Configuration Needed | x-request → use-x-chat | Configure request first, then use |
| Complete Customization | x-chat-provider → x-request → use-x-chat | Complete workflow |
🚨 Development Rules
Before using use-x-chat, must confirm:
- [ ] Has Provider source (choose one of the following):
- [ ] Has created custom Provider with x-chat-provider
- [ ] Decided to use built-in Provider (OpenAI/DeepSeek)
- [ ] @antdv-next/x-sdk is installed
- [ ] Understand MessageInfo data structure
- [ ] UI components are ready
Test Case Rules
- If the user does not explicitly need test cases, do not add test files
- Only create test cases when the user explicitly requests them
Code Quality Rules
- After completion, must check types: Run
tsc --noEmitto ensure no type errors - Keep code clean: Remove all unused variables and imports
🔗 Reference Resources
📚 Core Reference Documentation
- API.md - Complete API reference documentation
- EXAMPLES.md - All practical example code
🌐 SDK Official Documentation
💻 Example Code
- useXChat demos - Complete example demos
useXChat
```tsx | pure type useXChat< ChatMessage extends SimpleType = object, ParsedMessage extends SimpleType = ChatMessage, Input = RequestParams<ChatMessage>, Output = SSEOutput,
= (
config: XChatConfig<ChatMessage, ParsedMessage, Input, Output>, ) => XChatConfigReturnType;
<!-- prettier-ignore -->
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| ChatMessage | Message data type, defines the structure of chat messages | object | object | - |
| ParsedMessage | Parsed message type, message format for component consumption | ChatMessage | ChatMessage | - |
| Input | Request parameter type, defines the structure of request parameters | RequestParams\<ChatMessage\> | RequestParams\<ChatMessage\> | - |
| Output | Response data type, defines the format of received response data | SSEOutput | SSEOutput | - |
### XChatConfig
<!-- prettier-ignore -->
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| provider | Data provider used to convert data and requests of different structures into formats that useXChat can consume. The platform includes built-in `DefaultChatProvider` and `OpenAIChatProvider`, and you can also implement your own Provider by inheriting `AbstractChatProvider`. See: [Chat Provider Documentation](/sdk/chat-provider) | AbstractChatProvider\<ChatMessage, Input, Output\> | - | - |
| conversationKey | Session unique identifier (globally unique), used to distinguish different sessions | string | Symbol('ConversationKey') | - |
| defaultMessages | Default display messages | MessageInfo\<ChatMessage\>[] \| (info: { conversationKey?: string }) => MessageInfo\<ChatMessage\>[] \| (info: { conversationKey?: string }) => Promise\<MessageInfo\<ChatMessage\>[]\> | - | - |
| parser | Converts ChatMessage into ParsedMessage for consumption. When not set, ChatMessage is consumed directly. Supports converting one ChatMessage into multiple ParsedMessages | (message: ChatMessage) => BubbleMessage \| BubbleMessage[] | - | - |
| requestFallback | Fallback message for failed requests. When not provided, no message will be displayed | ChatMessage \| (requestParams: Partial\<Input\>,info: { error: Error; errorInfo: any; messages: ChatMessage[], message: ChatMessage }) => ChatMessage\|Promise\<ChatMessage\> | - | - |
| requestPlaceholder | Placeholder message during requests. When not provided, no message will be displayed | ChatMessage \| (requestParams: Partial\<Input\>, info: { messages: Message[] }) => ChatMessage \| Promise\<Message\> | - | - |
### XChatConfigReturnType
| Property | Description | Type | Default | Version |
| --------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------- | ------- |
| abort | Cancel request | () => void | - | - |
| isRequesting | Whether a request is in progress (Vue Ref) | Ref\<boolean\> | - | - |
| isDefaultMessagesRequesting | Whether the default message list is requesting (Vue Ref) | Ref\<boolean\> | false | - |
| messages | Current managed message list content (Vue Ref) | Ref\<MessageInfo\<ChatMessage\>[]\> | - | - |
| parsedMessages | Content translated through `parser` (Vue Ref) | Ref\<MessageInfo\<ParsedMessages\>[]\> | - | - |
| onReload | Regenerate, will send request to backend and update the message with new returned data | (id: string \| number, requestParams: Partial\<Input\>, opts: { extra: AnyObject }) => void | - | - |
| onRequest | Add a Message and trigger request | (requestParams: Partial\<Input\>, opts: { extra: AnyObject }) => void | - | - |
| setMessages | Directly modify messages without triggering requests | (messages: Partial\<MessageInfo\<ChatMessage\>\>[]) => void | - | - |
| setMessage | Directly modify a single message without triggering requests | (id: string \| number, info: Partial\<MessageInfo\<ChatMessage\>\>) => void | - | - |
| removeMessage | Deleting a single message will not trigger a request | (id: string \| number) => void | - | - |
| queueRequest | Will add the request to a queue, waiting for the conversationKey to be initialized before sending | (conversationKey: string \| symbol, requestParams: Partial\<Input\>, opts?: { extraInfo: AnyObject }) => void | - | - |
#### MessageInfo
interface MessageInfo<ChatMessage> { id: number | string; message: ChatMessage; status: MessageStatus; extra?: AnyObject; }
#### MessageStatus
type MessageStatus = | "local" | "loading" | "updating" | "success" | "error" | "abort";
1. Message Management
Get Message List
const { messages } = useXChat({ provider });
// messages is a Vue Ref: Ref<MessageInfo<MessageType>[]>
// Access via messages.value
// Actual message data is in msg.messageManually Set Messages
const { setMessages } = useXChat({ provider });
// Clear messages
setMessages([]);
// Add welcome message - note it's MessageInfo structure
setMessages([
{
id: "welcome",
message: {
content: "Welcome to AI Assistant",
role: "assistant",
},
status: "success",
},
]);Update Single Message
const { setMessage } = useXChat({ provider });
// Update message content - need to update message object
setMessage("msg-id", {
message: { content: "New content", role: "assistant" },
});
// Mark as error - update status
setMessage("msg-id", { status: "error" });2. Request Control
Send Message
const { onRequest } = useXChat({ provider });
// Basic usage
onRequest({ query: "User question" });
// With additional parameters
onRequest({
query: "User question",
context: "Previous conversation content",
userId: "user123",
});Abort Request
const { abort, isRequesting } = useXChat({ provider });
// In Vue template or TSX render function
<button onClick={abort} disabled={!isRequesting.value}>
Stop generation
</button>;Resend
The resend feature allows users to regenerate replies for specific messages, which is very useful when AI answers are unsatisfactory or errors occur.
Basic Usage
import { defineComponent } from "vue";
import { useXChat } from "@antdv-next/x-sdk";
const ChatComponent = defineComponent(() => {
const { messages, onReload } = useXChat({ provider });
return () => (
<div>
{messages.value.map(msg => (
<div key={msg.id}>
<span>{msg.message.content}</span>
{msg.message.role === "assistant" && (
<button onClick={() => onReload(msg.id)}>Regenerate</button>
)}
</div>
))}
</div>
);
});Resend Notes
1. Can only regenerate AI replies: Usually can only use resend on messages with role === 'assistant' 2. Status management: Resend will set the corresponding message status to loading 3. Parameter passing: Can pass additional information to Provider through extra parameter 4. Error handling: It is recommended to use requestFallback to handle resend failures
3. Error Handling
Unified Error Handling
const { messages } = useXChat({
provider,
requestFallback: (_, { error, errorInfo, messageInfo }) => {
// Network error
if (!navigator.onLine) {
return {
content: "Network connection failed, please check network",
role: "assistant" as const,
};
}
// User interruption
if (error.name === "AbortError") {
return {
content: messageInfo?.message?.content || "Reply cancelled",
role: "assistant" as const,
};
}
// Server error
return {
content:
errorInfo?.error?.message || "Network error, please try again later",
role: "assistant" as const,
};
},
});4. Message Display During Request
Generally no configuration is needed, default use with Bubble component's loading state. For custom loading content, refer to:
import { defineComponent } from "vue";
import { useXChat } from "@antdv-next/x-sdk";
const ChatComponent = defineComponent(() => {
const { messages, onRequest } = useXChat({ provider });
return () => (
<div>
{messages.value.map(msg => (
<div key={msg.id}>
{msg.message.role}: {msg.message.content}
</div>
))}
<button onClick={() => onRequest({ query: "Hello" })}>Send</button>
</div>
);
});Custom Request Placeholder
When requestPlaceholder is set, placeholder messages will be displayed before the request starts, used with Bubble component's loading state.
const { messages } = useXChat({
provider,
requestPlaceholder: (_, { error, messageInfo }) => {
return {
content: "Generating...",
role: "assistant",
};
},
});Complete Example Projects
Project with Conversation Management
import { defineComponent, ref } from "vue";
import { useXChat } from "@antdv-next/x-sdk";
import { chatProvider } from "../services/chatService";
import type { ChatMessage } from "../providers/ChatProvider";
import {
Bubble,
Sender,
Conversations,
type ConversationsProps,
} from "@antdv-next/x";
const App = defineComponent(() => {
const conversations = ref([{ key: "1", label: "New Conversation" }]);
const activeKey = ref("1");
const senderRef = ref<InstanceType<typeof Sender> | null>(null);
// Create new conversation
const handleNewConversation = () => {
const newKey = Date.now().toString();
conversations.value.push({
key: newKey,
label: `Conversation ${conversations.value.length + 1}`,
});
activeKey.value = newKey;
};
// Delete conversation
const handleDeleteConversation = (key: string) => {
const filtered = conversations.value.filter(item => item.key !== key);
if (filtered.length === 0) {
const newKey = Date.now().toString();
conversations.value = [{ key: newKey, label: "New Conversation" }];
} else {
conversations.value = filtered;
}
if (activeKey.value === key) {
activeKey.value = conversations.value[0]?.key || "1";
}
};
const { messages, onRequest, isRequesting, abort } = useXChat<
ChatMessage,
ChatMessage,
{ query: string },
{ content: string; time: string; status: "success" | "error" }
>({
provider: chatProvider,
conversationKey: activeKey,
requestFallback: (_, { error }) => {
if (error.name === "AbortError") {
return {
content: "Cancelled",
role: "assistant" as const,
timestamp: Date.now(),
};
}
return {
content: "Request failed",
role: "assistant" as const,
timestamp: Date.now(),
};
},
});
const menuConfig: ConversationsProps["menu"] = conversation => ({
items: [
{
label: "Delete",
key: "delete",
danger: true,
},
],
onClick: ({ key: menuKey }) => {
if (menuKey === "delete") {
handleDeleteConversation(conversation.key);
}
},
});
return () => (
<div style={{ display: "flex", height: "100vh" }}>
{/* Conversation List */}
<div
style={{
width: "240px",
borderRight: "1px solid #f0f0f0",
display: "flex",
flexDirection: "column",
}}
>
<Conversations
creation={{
onClick: handleNewConversation,
}}
items={conversations.value}
activeKey={activeKey.value}
menu={menuConfig}
onActiveChange={key => {
activeKey.value = key;
}}
/>
</div>
{/* Chat Area */}
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
<div
style={{
padding: "16px",
borderBottom: "1px solid #f0f0f0",
fontSize: "16px",
fontWeight: 500,
}}
>
{conversations.value.find(c => c.key === activeKey.value)?.label ||
"Conversation"}
</div>
<div style={{ flex: 1, padding: "16px", overflow: "auto" }}>
<Bubble.List
role={{
assistant: {
placement: "start",
},
user: {
placement: "end",
},
}}
items={messages.value.map(msg => ({
key: msg.id,
content: msg.message.content,
role: msg.message.role,
loading: msg.status === "loading",
}))}
/>
</div>
<div style={{ padding: "16px", borderTop: "1px solid #f0f0f0" }}>
<Sender
loading={isRequesting.value}
ref={senderRef}
onSubmit={(content: string) => {
onRequest({ query: content });
senderRef.value?.clear?.();
}}
onCancel={abort}
placeholder="Enter message..."
/>
</div>
</div>
</div>
);
});
export default App;With State Management Resend
import { defineComponent, ref } from "vue";
import { useXChat } from "@antdv-next/x-sdk";
import { Bubble, Sender } from "@antdv-next/x";
import { Button } from "antdv-next";
import { chatProvider } from "../services/chatService";
import type { ChatMessage } from "../providers/ChatProvider";
const ChatWithRegenerate = defineComponent(() => {
const senderRef = ref<InstanceType<typeof Sender> | null>(null);
const { messages, onReload, isRequesting, onRequest, abort } = useXChat<
ChatMessage,
ChatMessage,
{ query: string },
{ content: string; time: string; status: "success" | "error" }
>({
provider: chatProvider,
requestPlaceholder: {
content: "Thinking...",
role: "assistant",
timestamp: Date.now(),
},
requestFallback: (_, { error, errorInfo, messageInfo }) => {
if (error.name === "AbortError") {
return {
content: messageInfo?.message?.content || "Reply cancelled",
role: "assistant" as const,
timestamp: Date.now(),
};
}
return {
content:
errorInfo?.error?.message || "Network error, please try again later",
role: "assistant" as const,
timestamp: Date.now(),
};
},
});
// Track message ID being regenerated
const regeneratingId = ref<string | number | null>(null);
const handleRegenerate = (messageId: string | number): void => {
regeneratingId.value = messageId;
onReload(
messageId,
{},
{
extraInfo: { regenerate: true },
},
);
};
return () => (
<div>
<Bubble.List
role={{
assistant: {
placement: "start",
},
user: {
placement: "end",
},
}}
items={messages.value.map(msg => ({
key: msg.id,
content: msg.message.content,
role: msg.message.role,
loading: msg.status === "loading",
footer: msg.message.role === "assistant" && (
<Button
type="text"
size="small"
loading={regeneratingId.value === msg.id && isRequesting.value}
onClick={() => handleRegenerate(msg.id)}
disabled={isRequesting.value && regeneratingId.value !== msg.id}
>
{regeneratingId.value === msg.id ? "Generating..." : "Regenerate"}
</Button>
),
}))}
/>
<div>
<Sender
loading={isRequesting.value}
onSubmit={(content: string) => {
onRequest({ query: content });
senderRef.value?.clear?.();
}}
onCancel={abort}
ref={senderRef}
placeholder="Enter message..."
allowSpeech
prefix={
<Sender.Header
title="AI Assistant"
open={false}
styles={{
content: { padding: 0 },
}}
/>
}
/>
</div>
</div>
);
});
export default ChatWithRegenerate;Related skills
FAQ
How do I access messages from useXChat?
messages is typed Ref<MessageInfo<MessageType>[]>, not direct MessageType, so access it via messages.value.
What is the prerequisite for useXChat?
You must already have a custom Chat Provider, which is handled by the x-chat-provider skill.