@skillpet/chat-react
v0.11.5
Published
React SSE 流式 AI 对话面板组件 — 内置 i18n(7 语言)、品牌色主题、子智能体支持
Downloads
195
Maintainers
Readme
@skillpet/chat-react
文档
功能特性
- SSE 流式对话,实时显示 AI 思考过程与工具调用
- 子智能体(consult agent)多轮对话与工具步骤展示
- 结构化提问(ask_user)表单交互
ask_user选项支持description描述(v0.11,卡片式选项布局)- 流式排队发送 — AI 回复中可继续输入,消息自动排队按序发送(v0.6)
- 队列管理 — 编辑、删除、拖拽排序排队中的消息(v0.6)
- 附件增强 — 拖放文件上传、粘贴图片上传、图片缩略图预览(v0.6)
- 图片生成展示与选择(display / 单选 / 多选,v0.7)
readOnly只读模式:隐藏输入区,仅展示消息流(v0.9+)ChatPanelHandle:forwardRef暴露命令式 API,与readOnly组合使用(v0.10+)- 斜杠指令面板
- 内置 7 种语言(zh-CN、zh-TW、en、ja、ko、es、fr)
- 蓝色品牌色默认主题,支持深色/浅色模式
- CSS 变量完全自定义配色
- Markdown 渲染(GFM 语法)
- React 18+ 兼容
安装
npm install @skillpet/chat-react自动安装 @skillpet/chat-core(类型/SSE/i18n)及 lucide-react、react-markdown 等依赖。
快速开始
import { ChatPanel } from "@skillpet/chat-react";
import "@skillpet/chat-core/styles.css";
function App() {
return (
<ChatPanel
projectId="my-project"
config={{
api: {
baseUrl: "/api/chat",
deleteConversationUrl: "/api/chat/conversation",
},
getAccessToken: () => localStorage.getItem("token"),
}}
/>
);
}三层 API
Layer 1: 开箱即用
| 导出 | 说明 |
|------|------|
| ChatPanel | 主组件,包含完整聊天 UI |
| ChatProvider | 通过 Context 注入配置 |
| useChatConfig | 读取 Context 配置 |
| setChatLanguage | 切换 i18n 语言 |
Layer 2: 自定义组合
| 导出 | 说明 |
|------|------|
| useChatPanel | Headless hook,返回所有状态和操作 |
| MessageBubble | 消息气泡组件 |
| AskUserBlock | 结构化表单组件 |
| ThinkingBlock | AI 思考过程组件 |
| SlashCommandPalette | 斜杠指令面板组件 |
Layer 3: 底层原语
| 导出 | 说明 |
|------|------|
| processSSEStream | SSE 流处理(从 core 重导出) |
| parseHistoryMessages | 历史消息解析(从 core 重导出) |
ChatPanel Props
| Prop | 类型 | 必选 | 说明 |
|------|------|------|------|
| projectId | string | 是 | 项目/会话 ID |
| config | ChatPanelConfig | | API 地址、鉴权等配置 |
| quickStarters | string[] | | 空状态快捷开场文案 |
| emptyState | ChatPanelEmptyState | | 自定义空状态图标/标题/副标题 |
| extraSlashCommands | SlashCommand[] | | 追加斜杠指令 |
| onStatusChange | () => void | | SSE 流结束回调 |
| onResourceUpdated | (key, snapshot?) => void | | 资源更新回调 |
| onUploadAttachment | (file: File) => Promise<ChatAttachment> | | 自定义附件上传 |
| onDeleteAttachment | (id: string) => Promise<void> | | 自定义附件删除 |
| capVisibleOverride | string[] | | 覆盖能力可见列表(如 ["thinking", "queuedSend"]) |
| avatars | { botAvatarUrl?, userAvatarUrl? } | | 覆盖头像 |
| readOnly | boolean | | 只读模式,隐藏输入区与 quickStarter 按钮(v0.9+) |
| className | string | | 追加 CSS 类名 |
readOnly (v0.9.0+)
boolean | undefined,默认 false。
启用后 <ChatPanel> 进入"只读模式",仅展示消息流,不渲染底部输入区与空状态的 quickStarter 按钮。
适用于工作流运行态、历史回放、只读访客视图等场景。
<ChatPanel projectId="..." readOnly emptyState={{ title: "等待中…" }} />宿主仍可通过 useChatPanel hook 的 handleSend(payload, undefined, { suppressUserBubble: true })
程序化派发首条消息。
chatRef — ChatPanelHandle (v0.10.0+)
通过 forwardRef 暴露命令式 API,适用于 readOnly 模式下程序化控制消息流。
import { useRef } from "react";
import { ChatPanel, type ChatPanelHandle } from "@skillpet/chat-react";
const chatRef = useRef<ChatPanelHandle>(null);
// mount 后自动派发首条消息(不显示用户气泡)
useEffect(() => {
if (!chatRef.current) return;
chatRef.current.handleSend(
JSON.stringify({ action: "start" }),
undefined,
{ suppressUserBubble: true }
);
}, []);
// 外部 socket/进度更新消息列表
useEffect(() => {
chatRef.current?.setMessages(prev => syncProgress(prev, jobs));
}, [jobs]);
return <ChatPanel ref={chatRef} readOnly config={...} />;ChatPanelHandle API
| 方法 | 说明 |
|---|---|
| handleSend(msg?, attachments?, opts?) | 发送消息;opts.suppressUserBubble: true 隐藏用户气泡 |
| setMessages(updater) | 直接更新消息列表(外部进度同步等) |
| stopGeneration() | 中断当前 SSE 流 |
| scrollToBottom(animated?) | 滚动到底部 |
| getMessages() | 获取当前消息列表快照 |
ChatPanelConfig
| 字段 | 类型 | 必选 | 说明 |
|------|------|------|------|
| api.baseUrl | string | 是 | SSE / 历史接口基础 URL |
| api.deleteConversationUrl | string | 是 | 删除对话 URL |
| getAccessToken | () => string \| null \| Promise | 是 | 获取 Bearer token |
| accessToken | string \| null | | token 标识(变化时重载历史) |
| lang | string | | 语言代码 |
| components | ChatPanelComponents | | UI 组件开关 |
多配置共享
import { ChatProvider, ChatPanel } from "@skillpet/chat-react";
<ChatProvider config={config}>
<ChatPanel projectId="project-a" />
<ChatPanel projectId="project-b" />
</ChatProvider>排队发送(v0.6)
当后端 /init 接口返回 capabilities.queuedSend.enabled: true 时自动启用。在 AI 流式回复中用户可继续输入消息,消息进入队列依次发送。
useChatPanel 新增返回值:
| 字段 | 类型 | 说明 |
|------|------|------|
| queuedSendCap | QueuedSendCap \| null | 后端返回的队列能力配置 |
| queuedSendEnabled | boolean | 队列功能是否可用 |
| messageQueue | QueuedMessage[] | 当前排队中的消息列表 |
| enqueueMessage | (content, attachments?) => boolean | 加入队列 |
| removeQueuedMessage | (id) => void | 移除队列项并清理附件 |
| popQueuedMessage | (id) => QueuedMessage \| undefined | 弹出队列项(用于编辑,保留附件) |
| reorderQueue | (fromIndex, toIndex) => void | 拖拽排序 |
| clearQueue | () => void | 清空队列 |
附件交互支持:点击按钮上传、粘贴图片、拖放文件。
图片生成 (v0.7)
支持后端推送 AI 生成的图片,三种展示模式:
display:纯展示,点击放大single_select:单选一张后提交multi_select:多选(min~max 张)后提交
通过 SSE 事件 image_generating(加载态)和 image_generation(完成态)推送,useChatPanel 返回 handleImageSelect 处理选择结果。
详见 API 文档 中的「图片生成」章节。
自定义 UI
import { useChatPanel, MessageBubble } from "@skillpet/chat-react";
import "@skillpet/chat-core/styles.css";
function CustomChat({ config }) {
const chat = useChatPanel({ projectId: "xxx", config });
return (
<div className="skillpet-chat">
{chat.messages.map((msg) => (
<MessageBubble key={msg.id} msg={msg} />
))}
</div>
);
}主题定制
包自带蓝色品牌色默认主题。深色模式通过 .dark 类或 [data-theme="dark"] 自动切换。
.skillpet-chat {
--skillpet-chat-primary: oklch(0.6 0.22 145); /* 自定义主色 */
}shadcn 桥接
.skillpet-chat {
--skillpet-chat-primary: var(--primary);
--skillpet-chat-background: var(--background);
--skillpet-chat-foreground: var(--foreground);
--skillpet-chat-muted: var(--muted);
--skillpet-chat-muted-foreground: var(--muted-foreground);
--skillpet-chat-border: var(--border);
--skillpet-chat-radius: var(--radius);
}i18n
import { setChatLanguage } from "@skillpet/chat-react";
setChatLanguage("en"); // zh-CN | zh-TW | en | ja | ko | es | frCDN 使用
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@skillpet/chat-core/dist/index.umd.js"></script>
<script src="https://unpkg.com/@skillpet/chat-react/dist/index.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@skillpet/chat-core/dist/skillpet-chat.css" />
<script>
const { ChatPanel } = SkillpetChatReact;
// ...
</script>