@bdky/chat-pilot-kit
v1.0.3
Published
企业级 AI Agent 对话 SDK,框架无关,支持 SSE 流式对话与 WebSocket,内置 Agent 管理、消息处理管道与 NodeView 扩展机制
Readme
@bdky/chat-pilot-kit
English | 简体中文
一个无头、框架无关的 AI 聊天 SDK,支持 SSE 流式传输、可扩展的消息节点和插件化架构。
@bdky/chat-pilot-kit 是一个轻量级、灵活的 SDK,用于构建 AI 驱动的聊天应用。它提供完整的对话管理系统,支持流式传输、多模态内容处理和强大的扩展系统——所有这些都不强制使用任何 UI 框架。
✨ 特性
- 🎯 无头 & 框架无关 — 无 UI 依赖,可与 React/Vue/原生 JavaScript 配合使用
- 🌊 流式优先 — 内置 SSE 流式传输,支持首字节时间(TTFT)跟踪
- 🧩 可扩展节点系统 — 10 种内置节点类型 + 自定义扩展 API
- 🔌 插件架构 — MessageExtension 系统用于自定义消息处理
- 🎨 多模态支持 — 文本、Markdown、图片、文件、音频、视频、思考块、工具调用
- 📡 事件驱动 — 基于 Emittery 的事件系统,实现实时状态更新
- 💾 对话管理 — 导入/导出、会话管理、历史持久化
- 📘 完整 TypeScript 支持 — 开箱即用的完整类型定义
📦 安装
# npm
npm install @bdky/chat-pilot-kit reflect-metadata
# yarn
yarn add @bdky/chat-pilot-kit reflect-metadata
# pnpm
pnpm add @bdky/chat-pilot-kit reflect-metadata对等依赖:
reflect-metadata(依赖注入所需)
格式:
- ESM:
@bdky/chat-pilot-kit(.esm.js) - CJS:
@bdky/chat-pilot-kit(.cjs.js) - 包含 TypeScript 声明文件
🚀 快速开始
import 'reflect-metadata';
import {createChatPilotKit, BaseAgentService} from '@bdky/chat-pilot-kit';
import type {AgentMessageData} from '@bdky/chat-pilot-kit';
// 1. 定义自定义 AgentService
class MyAgentService extends BaseAgentService {
async query(text: string): Promise<void> {
const sessionId = this.sessionId();
const queryId = this.queryId();
// 模拟 SSE 流式传输
const chunks: AgentMessageData[] = [
{answer: 'Hello', nodeType: 'text', queryId, sessionId},
{answer: ' world!', nodeType: 'text', queryId, sessionId}
];
for (const chunk of chunks) {
this.onData(chunk);
}
this.onCompleted();
}
dispose(): void {
// 清理资源
}
}
// 2. 创建 ChatPilotKit 实例
const {controller, emitter} = createChatPilotKit({
agentService: MyAgentService
});
// 3. 订阅事件
emitter.on('conversation_change', payload => {
console.log('对话已更新:', payload);
});
// 4. 发送查询
await controller.query('Hello');🏗️ 核心概念
用户输入 → Controller.query()
→ AgentService.query() → AI 后端 (SSE)
→ AgentMessageData 数据块
→ Extension.canProcess() → Extension.process()
→ ConversationNode 创建/更新
→ 事件触发 → UI 订阅并渲染Controller
ChatPilotKitController 是与 SDK 交互的主要入口。
| 方法 | 参数 | 返回值 | 描述 |
|------|------|--------|------|
| query | text: string, options?: IQueryOptions | Promise<void> | 向 AI 代理发送文本查询 |
| queryWithAttachments | text: string, attachments: IAttachmentInput[], options?: IQueryOptions | Promise<void> | 发送带文件附件的查询 |
| interrupt | - | void | 中断当前查询 |
| clear | - | void | 清除所有对话 |
| dispose | - | void | 清理并销毁控制器 |
| getOptions | - | IResolvedOptions | 获取当前配置 |
| exportConversations | - | IConversationBeanSnapshot[] | 将所有对话导出为 JSON |
| importConversations | conversations: IConversationBeanInput[], options?: IImportOptions | void | 从 JSON 导入对话 |
Agent Service
扩展 BaseAgentService 以集成您的 AI 后端。
抽象方法(必须实现):
query(text: string): Promise<void>— 向 AI 后端发送查询dispose(): void— 清理资源
受保护方法(从您的实现中调用):
onData(data: AgentMessageData): void— 发出数据块onCompleted(): void— 标记查询完成onError(error: Error): void— 报告错误onTtft(timestamp: number): void— 报告首字节时间
工具方法:
sessionId(): string— 获取当前会话 IDqueryId(): string— 获取当前查询 IDsetSessionId(id: string): void— 设置会话 IDsetQueryId(id: string): void— 设置查询 IDabort(): void— 中止当前请求
AgentMessageData 接口:
interface AgentMessageData {
answer: string; // 消息文本内容
nodeType?: string; // 节点类型标识符(匹配 Extension.name)
nodeData?: Record<string, unknown>; // 节点特定数据
queryId: string; // 当前查询 ID
sessionId: string; // 当前会话 ID
}完整的 SSE 示例:
import {BaseAgentService} from '@bdky/chat-pilot-kit';
import {ky, sseHook} from '@bdky/chat-pilot-kit/http';
import type {AgentMessageData} from '@bdky/chat-pilot-kit';
class MySSEAgentService extends BaseAgentService {
private abortController: AbortController | null = null;
async query(text: string): Promise<void> {
this.abortController = new AbortController();
const sessionId = this.sessionId();
const queryId = this.queryId();
try {
await ky.post('https://api.example.com/chat', {
json: {message: text, sessionId, queryId},
signal: this.abortController.signal,
hooks: {
afterResponse: [
sseHook.afterResponse<AgentMessageData>({
onMessage: chunk => {
this.onData(chunk);
},
onComplete: () => {
this.onCompleted();
},
onError: error => {
this.onError(error);
}
})
]
}
});
}
catch (error) {
if (error.name !== 'AbortError') {
this.onError(error as Error);
}
}
}
dispose(): void {
this.abortController?.abort();
}
}对话与节点
ConversationBean 结构:
interface ConversationBean {
id: string; // 唯一对话 ID
role: 'client' | 'aiWorker'; // 对话角色
nodes: ConversationNode[]; // 消息节点数组
completed: boolean; // 对话是否完成
createdAt: number; // 创建时间戳
updatedAt: number; // 最后更新时间戳
}ConversationNode 基类:
所有消息节点都扩展 ConversationNode<TContent>:
abstract class ConversationNode<TContent = unknown> {
id: string;
type: string;
content: TContent;
completed: boolean;
createdAt: number;
updatedAt: number;
metadata?: Record<string, unknown>;
abstract toJSON(): IConversationNodeSnapshot<TContent>;
updateContent(content: TContent): void;
updateMetadata(metadata: Record<string, unknown>): void;
}内置节点类型:
| 节点类 | 类型字符串 | 内容类型 | 可流式 | 工厂方法 |
|--------|-----------|---------|--------|----------|
| TextNode | 'text' | string | 否 | TextNode.fromString(text) |
| MarkdownNode | 'markdown' | string | 是 | MarkdownNode.fromString(text) |
| ImageNode | 'image' | IImageContent | 否 | ImageNode.fromContent(content) |
| FileNode | 'file' | IFileContent | 否 | FileNode.fromContent(content) |
| AudioNode | 'audio' | IAudioContent | 否 | AudioNode.fromContent(content) |
| VideoNode | 'video' | IVideoContent | 否 | VideoNode.fromContent(content) |
| ThinkingBlockNode | 'thinking' | IThinkingContent | 是 | ThinkingBlockNode.fromContent(content) |
| ToolCallNode | 'tool_call' | IToolCallContent | 否 | ToolCallNode.fromContent(content) |
| GenericNode | 自定义 | unknown | 否 | new GenericNode(type, content) |
| StreamableGenericNode | 自定义 | unknown | 是 | new StreamableGenericNode(type, content) |
内容类型接口:
interface IImageContent {
url: string;
alt?: string;
width?: number;
height?: number;
}
interface IFileContent {
url: string;
fileName: string;
fileSize: number;
fileType: string;
}
interface IThinkingContent {
text: string;
collapsed?: boolean;
}
interface IAudioContent {
url: string;
duration?: number;
mimeType?: string;
}
interface IVideoContent {
url: string;
duration?: number;
poster?: string;
mimeType?: string;
}
interface IToolCallContent {
name: string;
arguments: Record<string, unknown>;
result?: unknown;
status: 'pending' | 'running' | 'completed' | 'error';
error?: string;
}事件
使用 createChatPilotKit() 返回的 emitter 订阅事件。
| 事件 | 载荷 | 描述 |
|------|------|------|
| ready | never | SDK 已初始化并准备就绪 |
| conversation_add | {conversationId, role, timestamp} | 创建了新对话 |
| conversation_change | IConversationChangePayload | 对话已更新(节点已更改) |
| node_add | {conversationId, node} | 向对话添加了新节点 |
| node_update | {conversationId, node} | 现有节点已更新 |
| error | IChatPilotKitError | 发生错误 |
| interrupt | {queryId, sessionId} | 查询已中断 |
| clear | never | 所有对话已清除 |
| ttft | ITtftPayload | 测量了首字节时间 |
| history_import | {count, position} | 对话已导入 |
使用示例:
const {emitter} = createChatPilotKit({agentService: MyAgentService});
emitter.on('conversation_change', payload => {
console.log('对话:', payload.conversationId);
console.log('节点:', payload.nodes);
console.log('已完成:', payload.completed);
});
emitter.on('error', error => {
console.error('错误:', error.message);
console.error('类别:', error.category);
console.error('严重性:', error.severity);
});
emitter.on('ttft', payload => {
console.log('首字节时间:', payload.totalLatency, 'ms');
});🔌 扩展
扩展处理传入的 AgentMessageData 数据块并创建/更新对话节点。
内置扩展
SDK 包含 8 个内置扩展(按优先级排序):
| 扩展 | 优先级 | 处理 | 创建节点 |
|------|--------|------|----------|
| ThinkingBlockExtension | 50 | nodeType: 'thinking' | ThinkingBlockNode |
| TextExtension | 100 | nodeType: 'text' | TextNode |
| ImageExtension | 100 | nodeType: 'image' | ImageNode |
| FileExtension | 100 | nodeType: 'file' | FileNode |
| AudioExtension | 100 | nodeType: 'audio' | AudioNode |
| VideoExtension | 100 | nodeType: 'video' | VideoNode |
| ToolCallExtension | 100 | nodeType: 'tool_call' | ToolCallNode |
| MarkdownExtension | 200 | nodeType: 'markdown' | MarkdownNode |
获取所有内置扩展:
import {getBuiltInExtensions} from '@bdky/chat-pilot-kit';
const extensions = getBuiltInExtensions();创建自定义扩展
使用 MessageExtension.create() 定义自定义扩展:
import {MessageExtension, GenericNode} from '@bdky/chat-pilot-kit';
import type {AgentMessageData} from '@bdky/chat-pilot-kit';
const ChartExtension = MessageExtension.create({
name: 'chart',
priority: 150,
streamable: false,
canProcess(data: AgentMessageData) {
return data.nodeType === 'chart';
},
process(data: AgentMessageData) {
// 根据数据创建并返回新节点
const content = {
type: data.nodeData?.chartType as string,
data: data.nodeData?.chartData
};
return new GenericNode('chart', content);
},
hydrate(snapshot) {
// 导入对话时从快照恢复节点
return new GenericNode(snapshot.type, snapshot.content);
},
addNodeView() {
return null; // 无头模式,无视图
}
});
// 在 createChatPilotKit 中使用
const {controller} = createChatPilotKit({
agentService: MyAgentService,
extensions: [ChartExtension]
});可流式扩展示例:
import {MessageExtension, StreamableGenericNode} from '@bdky/chat-pilot-kit';
const StreamingChartExtension = MessageExtension.create({
name: 'streaming_chart',
priority: 150,
streamable: true,
canProcess(data) {
return data.nodeType === 'streaming_chart';
},
process(data) {
// 创建初始空内容节点
return new StreamableGenericNode('streaming_chart', '');
},
onStreamAppend(node, data) {
// 数据块到达时追加内容
node.appendContent(data.answer);
},
onStreamEnd(node) {
// 流结束时标记为已完成
node.markCompleted();
},
hydrate(snapshot) {
const node = new StreamableGenericNode(snapshot.type, snapshot.content);
node.completed = snapshot.completed;
return node;
},
addNodeView() {
return null;
}
});扩展生命周期:
const MyExtension = MessageExtension.create({
name: 'my_extension',
priority: 100,
onCreate() {
console.log('扩展已初始化');
// 预加载依赖,设置资源
},
onDestroy() {
console.log('扩展已销毁');
// 清理资源
},
canProcess(data) {
return data.nodeType === 'my_type';
},
process(data) {
return new GenericNode('my_type', data.answer);
},
hydrate(snapshot) {
return new GenericNode(snapshot.type, snapshot.content);
},
addNodeView() {
return null;
}
});覆盖内置扩展
选项 1:使用 overrideExtensions 替换
const CustomMarkdownExtension = MessageExtension.create({
name: 'markdown', // 与内置扩展同名
priority: 200,
streamable: true,
canProcess(data) {
return data.nodeType === 'markdown';
},
process(data) {
// 自定义 markdown 处理
return MarkdownNode.fromString(data.answer || '');
},
onStreamAppend(node, data) {
// 自定义流式逻辑
node.appendContent(data.answer || '');
},
onStreamEnd(node) {
node.markCompleted();
},
hydrate(snapshot) {
return MarkdownNode.fromJSON(snapshot);
},
addNodeView() {
return null;
}
});
createChatPilotKit({
agentService: MyAgentService,
overrideExtensions: [CustomMarkdownExtension] // 替换内置 MarkdownExtension
});选项 2:使用 .extend() 扩展
import {MarkdownExtension} from '@bdky/chat-pilot-kit';
const EnhancedMarkdownExtension = MarkdownExtension.extend({
priority: 250, // 更改优先级
onStreamAppend(node, data) {
// 手动调用原始行为(如需要)
node.appendContent(data.answer || '');
// 添加自定义行为
console.log('增强的 markdown 流式处理:', data.answer);
}
});
createChatPilotKit({
agentService: MyAgentService,
overrideExtensions: [EnhancedMarkdownExtension]
});⚠️ 错误处理
SDK 提供了全面的错误管理系统。
ErrorManager API:
const {controller, emitter} = createChatPilotKit({agentService: MyAgentService});
// 订阅错误
emitter.on('error', (error: IChatPilotKitError) => {
console.error('错误:', error);
});错误类别:
enum ErrorCategory {
NETWORK = 'NETWORK', // 网络相关错误
TIMEOUT = 'TIMEOUT', // 请求超时
VALIDATION = 'VALIDATION', // 输入验证错误
SERVICE = 'SERVICE', // 后端服务错误
CONFIGURATION = 'CONFIGURATION', // 配置错误
INTERNAL = 'INTERNAL' // SDK 内部错误
}错误严重性:
enum ErrorSeverity {
LOW = 'LOW', // 轻微问题,可恢复
MEDIUM = 'MEDIUM', // 中等问题,可能影响用户体验
HIGH = 'HIGH', // 严重问题,需要关注
CRITICAL = 'CRITICAL' // 关键故障,系统不可用
}IChatPilotKitError 接口:
interface IChatPilotKitError {
code: string; // 错误代码(例如 'NETWORK_ERROR')
message: string; // 人类可读的消息
category: ErrorCategory; // 错误类别
severity: ErrorSeverity; // 严重性级别
source: 'agent' | 'upload' | 'extension' | 'controller' | 'conversation';
metadata?: Record<string, unknown>; // 附加上下文
originalError?: Error; // 原始错误对象
}使用示例:
emitter.on('error', error => {
if (error.severity === ErrorSeverity.CRITICAL) {
// 显示关键错误 UI
alert(`关键错误: ${error.message}`);
}
else if (error.category === ErrorCategory.NETWORK) {
// 重试逻辑
console.log('网络错误,正在重试...');
}
// 记录到监控服务
logToMonitoring(error);
});💾 对话持久化
导出和导入对话以实现持久化或迁移。
导出对话:
const snapshots = controller.exportConversations();
// 保存到 localStorage、数据库等
localStorage.setItem('conversations', JSON.stringify(snapshots));导入对话:
const snapshots = JSON.parse(localStorage.getItem('conversations') || '[]');
controller.importConversations(snapshots, {
position: 'prepend' // 或 'replace'
});IImportOptions:
interface IImportOptions {
position?: 'prepend' | 'replace'; // 默认: 'prepend'
}'prepend':在现有对话之前插入导入的对话'replace':替换所有现有对话
水合过程:
导入对话时,SDK 会:
- 解析 JSON 快照
- 将每个节点的
type与已注册的扩展匹配 - 调用扩展的
process()方法重新创建节点 - 恢复节点状态(内容、元数据、完成状态)
- 触发
history_import事件
完整的往返示例:
// 导出
const snapshots = controller.exportConversations();
const json = JSON.stringify(snapshots);
// 保存到后端
await fetch('/api/save-history', {
method: 'POST',
body: json,
headers: {'Content-Type': 'application/json'}
});
// 稍后:从后端加载
const response = await fetch('/api/load-history');
const loadedSnapshots = await response.json();
// 导入
controller.importConversations(loadedSnapshots, {
position: 'replace'
});🌊 流式传输
实现 IStreamableNode 的节点支持增量内容更新。
IStreamableNode 接口:
interface IStreamableNode<TChunk = string> {
appendContent(chunk: TChunk): void;
}类型守卫:
import {isStreamableNode} from '@bdky/chat-pilot-kit';
if (isStreamableNode(node)) {
node.appendContent('新内容');
}内置可流式节点:
MarkdownNode— 追加 markdown 文本ThinkingBlockNode— 追加思考过程文本StreamableGenericNode— 通用可流式节点
扩展中的流式传输工作原理:
const StreamingExtension = MessageExtension.create({
name: 'streaming_text',
priority: 100,
streamable: true,
canProcess(data) {
return data.nodeType === 'streaming_text';
},
process(data) {
// 创建初始可流式节点
return new StreamableGenericNode('streaming_text', data.answer || '');
},
onStreamAppend(node, data) {
// 数据块到达时追加内容
node.appendContent(data.answer);
},
onStreamEnd(node) {
// 流结束时标记为已完成
node.markCompleted();
},
hydrate(snapshot) {
const node = new StreamableGenericNode(snapshot.type, snapshot.content);
node.completed = snapshot.completed;
return node;
},
addNodeView() {
return null;
}
});MarkdownNode 流式传输示例:
import {MarkdownNode} from '@bdky/chat-pilot-kit';
const node = MarkdownNode.fromString('');
// 模拟流式传输
node.appendContent('# Hello\n');
node.appendContent('This is ');
node.appendContent('**streaming** ');
node.appendContent('markdown.');
console.log(node.content); // "# Hello\nThis is **streaming** markdown."🎨 NodeView 系统(框架集成)
NodeView 系统支持对话节点的框架特定渲染。
核心接口:
interface NodeViewProps<TNode extends ConversationNode = ConversationNode> {
node: TNode;
updateContent: (content: TNode['content']) => void;
updateMetadata: (metadata: Record<string, unknown>) => void;
completed: boolean;
role: 'client' | 'aiWorker';
conversation: ConversationBean;
destroy: () => void;
}
interface INodeView {
mount(container: HTMLElement): void;
update(props: NodeViewProps): void;
destroy(): void;
}
type NodeViewFactory<TNode extends ConversationNode = ConversationNode> =
(props: NodeViewProps<TNode>) => INodeView;如何创建框架适配器:
- 为每种节点类型实现
NodeViewFactory - 创建将节点类型映射到工厂的注册表
- 使用框架特定组件渲染节点
- 订阅
conversation_change事件以触发重新渲染
参考实现:
查看 @bdky/chat-pilot-kit-react 以获取完整的 React 适配器实现,包括:
ChatPilotKitProvider上下文提供者useChatPilotKit()hook- 所有节点类型的内置 NodeView 组件
- TypeScript 支持
🌐 HTTP 工具
SDK 重新导出来自 ky 和 @bdky/ky-sse-hook 的 HTTP 工具以方便使用。
子路径导出:
import {ky, sseHook, HTTPError, TimeoutError} from '@bdky/chat-pilot-kit/http';
import type {KyInstance, Options} from '@bdky/chat-pilot-kit/http';从 ky 重新导出:
ky(默认导出)— HTTP 客户端HTTPError、TimeoutError— 错误类- 所有 TypeScript 类型
从 @bdky/ky-sse-hook 重新导出:
sseHook— ky 的 SSE 流式传输 hook
在 AgentService 中使用:
import {BaseAgentService} from '@bdky/chat-pilot-kit';
import {ky, sseHook} from '@bdky/chat-pilot-kit/http';
class MyAgentService extends BaseAgentService {
async query(text: string): Promise<void> {
await ky.post('https://api.example.com/chat', {
json: {message: text},
hooks: {
afterResponse: [
sseHook.afterResponse({
onMessage: chunk => this.onData(chunk),
onComplete: () => this.onCompleted(),
onError: error => this.onError(error)
})
]
}
});
}
dispose(): void {}
}⚙️ 配置参考
IOptions 接口:
interface IOptions<AS extends BaseAgentService = BaseAgentService> {
agentService: Newable<AS>; // 必需:您的 AgentService 类
enableDebugMode?: boolean; // 默认: false
sessionTimeout?: number; // 默认: 300000(5 分钟)
extensions?: MessageExtensionInstance[]; // 自定义扩展(追加)
overrideExtensions?: MessageExtensionInstance[]; // 覆盖内置扩展
}IQueryOptions 接口:
interface IQueryOptions {
sessionId?: string; // 自定义会话 ID
queryId?: string; // 自定义查询 ID
streaming?: boolean; // 启用流式传输(默认: true)
metadata?: Record<string, unknown>; // 自定义元数据
}IAttachmentInput 接口:
interface IAttachmentInput {
url: string; // 文件 URL(已上传)
fileName: string; // 文件名
fileSize: number; // 文件大小(字节)
fileType: string; // MIME 类型
metadata?: Record<string, unknown>; // 自定义元数据
}使用示例:
const {controller} = createChatPilotKit({
agentService: MyAgentService,
enableDebugMode: true,
sessionTimeout: 600000, // 10 分钟
extensions: [CustomExtension],
overrideExtensions: [EnhancedMarkdownExtension]
});
await controller.query('Hello', {
sessionId: 'custom-session-123',
queryId: 'query-456',
streaming: true,
metadata: {source: 'web-app'}
});
await controller.queryWithAttachments(
'分析这张图片',
[
{
url: 'https://example.com/image.jpg',
fileName: 'image.jpg',
fileSize: 102400,
fileType: 'image/jpeg'
}
],
{metadata: {feature: 'image-analysis'}}
);📘 TypeScript
SDK 使用 TypeScript 编写,并提供完整的类型定义。
类型导入:
import type {
// 核心
IChatPilotKitController,
IChatPilotKitEmitter,
IOptions,
IResolvedOptions,
// Agent
AgentMessageData,
NBaseAgentService,
// 节点
ConversationNode,
IConversationNodeSnapshot,
IConversationNodeInput,
IStreamableNode,
// 节点内容
IImageContent,
IFileContent,
IThinkingContent,
IAudioContent,
IVideoContent,
IToolCallContent,
ToolCallStatus,
// 对话
ConversationRole,
NConversationBean,
IConversationBeanSnapshot,
IConversationBeanInput,
// 扩展
MessageExtensionConfig,
MessageExtensionInstance,
// 事件
IConversationChangePayload,
ITtftPayload,
// 错误
IChatPilotKitError,
ICreateErrorParams,
ErrorCategory,
ErrorSeverity,
// NodeView
NodeViewProps,
NodeViewFactory,
INodeView,
// 查询
IQueryOptions,
IImportOptions,
IAttachmentInput,
// 节点数据
IConversationNodeData,
ITextNodeData,
IMarkdownNodeData,
IImageNodeData,
IFileNodeData,
IThinkingNodeData,
IAudioNodeData,
IVideoNodeData,
IToolCallNodeData,
IBuiltInNodeData
} from '@bdky/chat-pilot-kit';关键类型导出:
- Controller:
IChatPilotKitController - Emitter:
IChatPilotKitEmitter - Agent:
AgentMessageData、NBaseAgentService - 节点:
ConversationNode、IStreamableNode、所有内容接口 - 扩展:
MessageExtensionConfig、MessageExtensionInstance - 错误:
IChatPilotKitError、ErrorCategory、ErrorSeverity - 事件:
IConversationChangePayload、ITtftPayload
🔗 框架适配器
官方框架适配器可用:
| 包 | 框架 | 描述 |
|----|------|------|
| @bdky/chat-pilot-kit-react | React 19+ | React hooks、Provider 和 NodeView 组件 |
| @bdky/chat-pilot-kit-vue3 | Vue 3 | Vue composables 和组件 |
React 示例:
import {ChatPilotKitProvider, useChatPilotKit} from '@bdky/chat-pilot-kit-react';
function App() {
return (
<ChatPilotKitProvider agentService={MyAgentService}>
<ChatUI />
</ChatPilotKitProvider>
);
}
function ChatUI() {
const {controller, conversations} = useChatPilotKit();
return (
<div>
{conversations.map(conv => (
<div key={conv.id}>
{conv.nodes.map(node => (
<NodeView key={node.id} node={node} />
))}
</div>
))}
</div>
);
}有关详细文档,请参阅适配器包的 README。
🌍 浏览器支持
| 浏览器 | 版本 | |--------|------| | Chrome | ≥ 74 | | Firefox | ≥ 90 | | Safari | ≥ 14.1 | | Edge | ≥ 79 | | iOS Safari | ≥ 14.1 | | Android Chrome | ≥ 74 |
📄 许可证
MIT
Made with ❤️ by 百度智能云客悦 Ky-FE Team
