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-react

v1.0.5

Published

chat-pilot-kit 的 React 封装,提供 Provider、Context、Hooks 和 ReactNodeViewRenderer

Downloads

318

Readme

@bdky/chat-pilot-kit-react

npm version License: MIT TypeScript

English | 简体中文

@bdky/chat-pilot-kit 的 React 适配层,提供 Provider、Hooks、NodeView 组件和国际化支持,用于构建 AI 聊天界面。

✨ 特性

  • 🎯 开箱即用的 NodeView — 8 种内置节点渲染组件(文本、Markdown、思考块、工具调用、图片、文件、音频、视频)
  • 🪝 React HooksuseConversationsuseChatPilotKitEventsuseNodeInteraction
  • 🎨 高度可定制 — 通过 classNamestyleslots 对内置组件进行二次扩展,无需完全替换
  • 🌍 国际化 — 内置中英文,支持自定义翻译
  • 🎨 主题系统 — CSS 自定义属性,支持亮色/暗色模式及 data-theme 切换
  • 📘 完整 TypeScript 支持 — 开箱即用的完整类型定义

📦 安装

# npm
npm install @bdky/chat-pilot-kit-react @bdky/chat-pilot-kit

# yarn
yarn add @bdky/chat-pilot-kit-react @bdky/chat-pilot-kit

对等依赖: React ≥ 16.8

🚀 快速开始

import {createChatPilotKit, BaseAgentService} from '@bdky/chat-pilot-kit';
import {
    ChatPilotKitProvider,
    useConversations,
    useChatPilotKit,
    NodeRenderer,
    getDefaultReactExtensions,
} from '@bdky/chat-pilot-kit-react';
import '@bdky/chat-pilot-kit-react/styles.css';

// 1. 实现你的 AgentService
class MyAgentService extends BaseAgentService {
    async query(text: string): Promise<void> {
        // 调用 AI 后端并流式返回数据
        this.onData({answer: 'Hello!', nodeType: 'markdown', queryId: this.queryId(), sessionId: this.sessionId()});
        this.onCompleted();
    }
    dispose(): void {}
}

// 2. 创建 Controller
const controller = createChatPilotKit({
    agentService: MyAgentService,
    extensions: getDefaultReactExtensions(),
});

// 3. 包裹应用
export default function App() {
    return (
        <ChatPilotKitProvider controller={controller}>
            <Chat />
        </ChatPilotKitProvider>
    );
}

// 4. 构建聊天 UI
function Chat() {
    const {controller} = useChatPilotKit();
    const conversations = useConversations();

    return (
        <div>
            {conversations.map(conv =>
                conv.nodes.map(node => (
                    <NodeRenderer
                        key={node.id}
                        node={node}
                        conversation={conv.bean}
                    />
                ))
            )}
            <button onClick={() => controller.query('你好')}>发送</button>
        </div>
    );
}

🎨 样式

在应用入口处引入一次内置 CSS:

import '@bdky/chat-pilot-kit-react/styles.css';

📖 API 参考

ChatPilotKitProvider

Context Provider,将 Controller 注入到所有子组件。

<ChatPilotKitProvider controller={controller}>
    {children}
</ChatPilotKitProvider>

| Prop | 类型 | 说明 | |------|------|------| | controller | ChatPilotKitController | 由 createChatPilotKit() 创建的控制器 | | children | ReactNode | — |


Hooks

useChatPilotKit()

从 Context 中获取 Controller。若在 ChatPilotKitProvider 外部调用会抛出错误。

const {controller} = useChatPilotKit();

await controller.query('你好');
await controller.queryWithAttachments('分析这个文件', attachments);
controller.interrupt();
controller.clear();
controller.importConversations(inputs, {position: 'prepend'});
const snapshots = controller.exportConversations();

useConversations()

返回响应式的对话列表,自动与 Controller 状态同步。

const conversations = useConversations();
// conversations: IConversationItem[]
// 每项包含: { conversationId, role, nodes, completed, bean }

useChatPilotKitEvents(props)

订阅 Controller 生命周期事件,所有回调均为可选。

useChatPilotKitEvents({
    onReady: () => {},
    onConversationAdd: (payload) => {},
    onConversationChange: (payload) => {
        if (payload.completed && payload.role === 'aiWorker') {
            setLoading(false);
        }
    },
    onNodeAdd: (payload) => {},
    onNodeUpdate: (payload) => {},
    onError: (payload) => { console.error(payload); },
    onInterrupt: () => {},
    onClear: () => {},
    onTtft: (payload) => {},
    onHistoryImport: (payload) => {},
    onNodeInteraction: (payload) => {},
});

useNodeInteraction(props)

与 NodeView 组件进行双向通信——监听交互事件并向节点发送命令。

const {sendCommand} = useNodeInteraction({
    filter: 'click',  // string | string[] | (type: string) => boolean
    onInteraction: (payload) => {
        console.log(payload.type, payload.data, payload.nodeId);
    },
});

// 向指定节点发送命令
sendCommand(nodeId, 'highlight', {color: 'yellow'});

NodeView 系统

NodeView 是渲染单个对话节点的 React 组件。SDK 内置 8 种 NodeView,并提供自定义注册机制。

NodeRenderer

使用节点注册的 NodeView 渲染单个 ConversationNode

<NodeRenderer node={node} conversation={conv.bean} />

内置 Extensions

一次性注册所有内置 NodeView:

import {getDefaultReactExtensions} from '@bdky/chat-pilot-kit-react';

const controller = createChatPilotKit({
    extensions: getDefaultReactExtensions(),
});

也可以单独注册:

import {
    ReactTextExtension,
    ReactMarkdownExtension,
    ReactThinkingBlockExtension,
    ReactToolCallExtension,
    ReactImageExtension,
    ReactFileExtension,
    ReactAudioExtension,
    ReactVideoExtension,
} from '@bdky/chat-pilot-kit-react';

自定义 NodeView

替换内置 NodeView 或注册全新的节点类型:

import {
    ReactMarkdownExtension,
    ReactNodeViewRenderer,
    MarkdownNodeView,
} from '@bdky/chat-pilot-kit-react';
import type {NodeViewProps, MarkdownNode} from '@bdky/chat-pilot-kit';
import type {FC} from 'react';

// 包装内置 NodeView,注入自定义 props
const MyMarkdown: FC<NodeViewProps<MarkdownNode>> = (props) => (
    <MarkdownNodeView {...props} className="my-markdown" />
);

// 或完全自定义
const CustomMarkdown: FC<NodeViewProps<MarkdownNode>> = ({node}) => (
    <div className="custom">{node.content}</div>
);

const MyMarkdownExtension = ReactMarkdownExtension.extend({
    addNodeView() {
        return ReactNodeViewRenderer(MyMarkdown);
    }
});

NodeView 扩展 Props

所有内置 NodeView 组件均支持可选的扩展 props,无需完全替换组件即可进行二次定制。

通用 Props(所有 NodeView 均支持)

| Prop | 类型 | 说明 | |------|------|------| | className | string | 追加到根元素,与内置 BEM 类名共存 | | style | CSSProperties | 合并到根元素的内联样式 | | dataAttributes | Record<\data-${string}`, string | number | boolean>| 透传到根元素的data-*` 属性 |

ThinkingBlockNodeView

<ThinkingBlockNodeView
    {...props}
    defaultOpen={false}
    slots={{
        icon: <MyIcon />,
        label: <span>思考中...</span>,
        content: (text) => <pre className="custom-pre">{text}</pre>,
    }}
/>

| Prop | 类型 | 默认值 | |------|------|--------| | defaultOpen | boolean | true | | slots.icon | ReactNode | 内置灯泡 SVG | | slots.label | ReactNode | i18n 标签 | | slots.content | (text: string) => ReactNode | <pre> 块 |

ToolCallNodeView

<ToolCallNodeView
    {...props}
    defaultOpen={true}
    slots={{
        icon: <TerminalIcon />,
        badge: (status, label) => <MyBadge status={status}>{label}</MyBadge>,
        argsContent: (args) => <JsonViewer data={args} />,
        resultContent: (result) => <JsonViewer data={result} />,
        errorContent: (error) => <Alert type="error">{error}</Alert>,
    }}
/>

| Prop | 类型 | 默认值 | |------|------|--------| | defaultOpen | boolean | false | | slots.icon | ReactNode | 内置终端 SVG | | slots.badge | (status: ToolCallStatus, label: string) => ReactNode | 内置 badge | | slots.argsContent | (args: unknown) => ReactNode | JSON <pre> | | slots.resultContent | (result: unknown) => ReactNode | JSON <pre> | | slots.errorContent | (error: string) => ReactNode | 错误 <div> |

ImageNodeView

| Prop | 类型 | |------|------| | slots.image | (props: {src, alt, width?, height?}) => ReactNode | | slots.caption | (alt: string) => ReactNode |

FileNodeView

| Prop | 类型 | |------|------| | slots.icon | (fileType: string) => ReactNode | | slots.downloadIcon | ReactNode |

AudioNodeView

| Prop | 类型 | 说明 | |------|------|------| | audioProps | AudioHTMLAttributes<HTMLAudioElement> | 透传到 <audio> 元素的原生属性 |

VideoNodeView

| Prop | 类型 | 说明 | |------|------|------| | videoProps | VideoHTMLAttributes<HTMLVideoElement> | 透传到 <video> 元素的原生属性 |

TextNodeViewMarkdownNodeView 仅支持通用 Props,无 slots。


国际化

内置 NodeView(ThinkingBlock、ToolCall)开箱支持中英文。

import {CpkTranslationsProvider} from '@bdky/chat-pilot-kit-react';

<CpkTranslationsProvider locale="zh-CN">
    {/* ThinkingBlockNodeView 和 ToolCallNodeView 将使用中文标签 */}
    <App />
</CpkTranslationsProvider>

覆盖特定文案:

<CpkTranslationsProvider
    locale="zh-CN"
    translations={{
        thinkingBlockLabel: '推理中',
        toolCallStatusRunning: '执行中...',
    }}
>
    <App />
</CpkTranslationsProvider>

可覆盖的 key:thinkingBlockLabeltoolCallStatusPendingtoolCallStatusRunningtoolCallStatusCompletedtoolCallStatusErrortoolCallArgumentstoolCallResult


主题定制

NodeView 样式使用 --cpk-node-* 命名空间下的 CSS 自定义属性。覆盖这些变量即可统一定制所有 NodeView 的外观:

:root {
    --cpk-node-surface: #ffffff;
    --cpk-node-text-primary: #111827;
    --cpk-node-accent: #2563eb;
    --cpk-node-panel-bg: #f9fafb;
    --cpk-node-border: #e5e7eb;
}

[data-theme='dark'] {
    --cpk-node-surface: #1e1e2e;
    --cpk-node-text-primary: #cdd6f4;
    --cpk-node-accent: #89b4fa;
    --cpk-node-panel-bg: #181825;
    --cpk-node-border: #313244;
}

主题系统同时支持 prefers-color-scheme 媒体查询和祖先元素上的 data-theme="light" | "dark" 属性显式切换。


📘 TypeScript

所有类型均从包根路径导出:

import type {
    // 来自 @bdky/chat-pilot-kit(重新导出)
    NodeViewProps,
    ConversationNode,
    ConversationBean,
    ConversationRole,
    IConversationBeanInput,
    IAttachmentInput,
    INodeInteractionPayload,
    INodeViewCommand,
    BaseAgentService,

    // React 专属
    ReactNodeViewComponent,
    NodeViewExtensionProps,
    ThinkingBlockNodeViewExtProps,
    ToolCallNodeViewExtProps,
    ImageNodeViewExtProps,
    FileNodeViewExtProps,
    AudioNodeViewExtProps,
    VideoNodeViewExtProps,
    ToolCallStatus,
    CpkTranslations,
} from '@bdky/chat-pilot-kit-react';

🔗 相关包

| 包 | 说明 | |----|------| | @bdky/chat-pilot-kit | 核心无头 SDK,框架无关 | | @bdky/chat-pilot-kit-vue3 | Vue 3 适配层 |


📄 许可证

MIT © Baidu Keyue Team


Made with ❤️ by 百度智能云客悦 Ky-FE Team