npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bdky/chat-pilot-kit

v1.0.3

Published

企业级 AI Agent 对话 SDK,框架无关,支持 SSE 流式对话与 WebSocket,内置 Agent 管理、消息处理管道与 NodeView 扩展机制

Readme

@bdky/chat-pilot-kit

npm version License: MIT TypeScript

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 — 获取当前会话 ID
  • queryId(): string — 获取当前查询 ID
  • setSessionId(id: string): void — 设置会话 ID
  • setQueryId(id: string): void — 设置查询 ID
  • abort(): 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 会:

  1. 解析 JSON 快照
  2. 将每个节点的 type 与已注册的扩展匹配
  3. 调用扩展的 process() 方法重新创建节点
  4. 恢复节点状态(内容、元数据、完成状态)
  5. 触发 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;

如何创建框架适配器:

  1. 为每种节点类型实现 NodeViewFactory
  2. 创建将节点类型映射到工厂的注册表
  3. 使用框架特定组件渲染节点
  4. 订阅 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 客户端
  • HTTPErrorTimeoutError — 错误类
  • 所有 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: AgentMessageDataNBaseAgentService
  • 节点: ConversationNodeIStreamableNode、所有内容接口
  • 扩展: MessageExtensionConfigMessageExtensionInstance
  • 错误: IChatPilotKitErrorErrorCategoryErrorSeverity
  • 事件: IConversationChangePayloadITtftPayload

🔗 框架适配器

官方框架适配器可用:

| 包 | 框架 | 描述 | |----|------|------| | @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