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

@fses/ai-chat

v0.2.15

Published

基于 Vue 3 的 AI 对话组件,支持 SSE 流式响应、多轮会话管理、Markdown 渲染、工具调用状态展示和结构化图表卡片渲染。

Readme

@fses/ai-chat

基于 Vue 3 的 AI 对话组件,支持 SSE 流式响应、多轮会话管理、Markdown 渲染、工具调用状态展示和结构化图表卡片渲染。

安装

pnpm add @fses/ai-chat

对等依赖

宿主项目需要提供以下依赖:

pnpm add vue@^3.5.32 ant-design-vue@^4.2.6 @ant-design/icons-vue@^6.0.0 @opentiny/tiny-robot@^0.4.1 @opentiny/tiny-robot-svgs@^0.4.1 marked@^18.0.0 echarts@^5.4.0

快速开始

方式一:Vue 插件

全局注册组件并配置 API,之后可在任意模板中直接使用 <FsesAiChat />

// main.ts
import { createApp } from 'vue'
import Antd from 'ant-design-vue'
import { FsesAiChatPlugin } from '@fses/ai-chat'
import 'ant-design-vue/dist/reset.css'
import '@fses/ai-chat/dist/style.css'
import App from './App.vue'

const app = createApp(App)

app.use(Antd)
app.use(FsesAiChatPlugin, {
  apiBaseUrl: '/ai/runtime/api',
  enableChartCards: true,
  headers: () => ({
    Authorization: `Bearer ${getToken()}`,
  }),
  onError: (err) => {
    console.error('[Chat Error]', err)
  },
})

app.mount('#app')

在模板中使用:

<template>
  <div style="width: 100%; height: 100vh;">
    <FsesAiChat />
  </div>
</template>

方式二:独立组件

按需引入组件,通过 Props 逐个配置。

<script setup lang="ts">
import { FsesAiChat } from '@fses/ai-chat'
import '@fses/ai-chat/dist/style.css'

function getToken() {
  return localStorage.getItem('token') || ''
}
</script>

<template>
  <FsesAiChat
    api-base-url="/ai/runtime/api"
    enable-chart-cards
    :headers="() => ({ Authorization: `Bearer ${getToken()}` })"
    :on-error="(err) => console.error(err)"
    placeholder="请输入问数需求..."
    welcome-text="欢迎使用 AI 助手"
  />
</template>

方式三:Headless

直接使用 useChat composable,自行构建界面。

import { useChat } from '@fses/ai-chat'

const chat = useChat({
  apiBaseUrl: '/ai/runtime/api',
  enableChartCards: true,
  headers: () => ({ Authorization: `Bearer ${getToken()}` }),
  onConversationChange(id) {
    console.log('切换到会话', id)
  },
  onError(err) {
    console.error(err)
  },
})

await chat.sendMessage('本月回款趋势怎么样?')

console.log(chat.messages.value)
console.log(chat.isLoading.value)

图表卡片

开启 enableChartCards 后,助手消息可以携带 cards?: ChartCardSpec[]。组件会先渲染 Markdown 正文,再在正文下方渲染结构化图表卡片。

一张图表卡片包含标题、统计周期、一个主图表、摘要、数据来源、权限说明、标准动作按钮和可选版本信息。图表区域由前端通过 ECharts 渲染,后端只需要返回稳定的 ChartCardSpec 数据。

ChartCardSpec

export interface ChartCardSpec {
  type: 'chart-card'
  id: string
  title: string
  period?: string
  chart: {
    type: 'mini-bar' | 'bar' | 'line' | 'area' | 'pie' | 'grouped-bar'
    xField: string
    yFields: string[]
    data: Record<string, unknown>[]
    sort?: 'none' | 'asc' | 'desc'
    limit?: number
    hiddenSeries?: string[]
  }
  summary?: string
  source: {
    label: string
    value?: string
  }
  permission: {
    label: string
    level?: 'self' | 'team' | 'org'
    downloadable?: boolean
  }
  actions?: Array<'view' | 'download' | 'insert-left' | 'save-doc' | 'save-kb' | 'upgrade'>
  meta?: {
    generatedBy?: 'agent'
    prompt?: string
    version?: number
  }
}

API

Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | apiBaseUrl | string | 插件配置或 '' | API 基础地址 | | headers | () => Record<string, string> | 插件配置 | 请求头生成函数 | | onError | (error: Error) => void | 插件配置 | 错误回调 | | enableChartCards | boolean | false | 是否启用结构化图表卡片渲染 | | placeholder | string | '请输入消息...' | 输入框占位文字 | | welcomeText | string | '开始新的对话' | 无消息时的欢迎文字 |

Props 优先级高于插件配置,未传入的 Props 会从插件配置中读取。

插件配置

| 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | apiBaseUrl | string | 是 | API 基础地址 | | headers | () => Record<string, string> | 否 | 请求头生成函数,每次请求前调用 | | onError | (error: Error) => void | 否 | 全局错误回调 | | enableChartCards | boolean | 否 | 是否默认启用图表卡片能力 |

useChat Composable

参数

| 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | apiBaseUrl | string | 是 | API 基础地址 | | headers | () => Record<string, string> | 否 | 请求头生成函数 | | enableChartCards | boolean | 否 | 是否保留并渲染结构化图表卡片 | | onConversationChange | (id: string) => void | 否 | 会话切换回调 | | onError | (error: Error) => void | 否 | 错误回调 |

返回值

| 字段 | 类型 | 说明 | |------|------|------| | conversations | Ref<Conversation[]> | 所有会话列表 | | currentConversationId | Ref<string \| null> | 当前活跃会话 ID | | messages | Ref<ChatMessage[]> | 当前会话的消息列表 | | isLoading | Ref<boolean> | 是否正在请求中 | | streamingMessageId | Ref<string \| null> | 当前正在流式输出的消息 ID | | sendMessage | (content: string) => Promise<void> | 发送消息 | | abortStream | () => void | 中止当前流式请求 | | createConversation | () => Promise<string> | 创建新会话,返回会话 ID | | deleteConversation | (id: string) => Promise<void> | 删除会话 | | renameConversation | (id: string, name: string) => Promise<void> | 重命名会话 | | switchConversation | (id: string) => Promise<void> | 切换会话并加载历史 | | loadHistory | (id: string) => Promise<void> | 加载指定会话的消息历史 |

类型定义

interface ChatMessage {
  id: string
  role: 'user' | 'assistant' | 'status'
  content: string
  loading?: boolean
  error?: string
  detail?: string
  timestamp: string
  startTime?: number
  cards?: ChartCardSpec[]
}

interface Conversation {
  id: string
  title: string
  messages: ChatMessage[]
}

后端 API 约定

组件依赖以下后端接口:

| 方法 | 路径 | 说明 | |------|------|------| | GET | {apiBaseUrl}/chat/conversations | 获取会话列表 | | GET | {apiBaseUrl}/chat/{id}/history | 获取会话消息历史 | | POST | {apiBaseUrl}/chat | 发送消息,返回 SSE 流式响应 | | DELETE | {apiBaseUrl}/chat/{id} | 删除会话 | | PATCH | {apiBaseUrl}/chat/{id}/title | 重命名会话,请求体:{ title: string } |

SSE 事件协议

POST /chat 返回 SSE 流式响应,支持以下事件类型:

| 事件类型 | 数据字段 | 说明 | |----------|----------|------| | start-step | 无 | 开始一个新的回复步骤,创建空消息 | | text-delta | delta | 增量文本,追加到当前消息 | | text-end | 无 | 文本生成结束 | | finish-step | 无 | 当前步骤完成 | | tool-input-start | toolName, toolCallId | 工具开始执行,显示状态条 | | tool-output-available | toolCallId, duration | 工具执行成功 | | tool-output-error | toolCallId, error, duration | 工具执行失败 | | data-oh:subagent.start | agentName, taskId | 子代理开始执行 | | data-oh:subagent.done | taskId, duration | 子代理执行完成 | | error | message | 服务端错误 |

工具名称映射

组件将内部工具名映射为中文标签展示:

| 工具名 | 显示标签 | |--------|----------| | load_ontology | 加载本体知识 | | get_connection_config | 获取数据源配置 | | search_business_glossary | 搜索术语表 | | match_metrics | 匹配指标 | | match_dimensions | 匹配维度 | | validate_sql | 校验 SQL | | explain_plan | 分析执行计划 | | execute_sql_api | 执行 SQL 查询 | | skill | 调用技能 | | task | 执行子任务 |

功能特性

  • SSE 流式响应:实时展示 AI 回复,支持中止
  • 多会话管理:创建、切换、重命名、删除会话
  • Markdown 渲染:支持 GFM 表格、代码块、列表、引用等
  • 工具调用展示:可视化工具执行状态和耗时
  • 子代理状态:展示子代理执行进度
  • 图表卡片:基于结构化 ChartCardSpec 渲染业务图表卡片
  • 安全渲染:通过 DOMPurify 对 Markdown HTML 进行安全过滤,不执行用户提供的 HTML、CSS、JavaScript 或原始 ECharts option
  • 自动滚动:新消息到达时自动滚动到底部
  • 错误处理:流式错误和工具错误均有独立展示
  • 快速操作:首次使用时提供快捷提问按钮

TinyRobotPage 演示

apps/web-agent/src/pages/TinyRobotPage.vue 作为集成演示页面,只负责开启图表卡片能力:

<script setup lang="ts">
import { FsesAiChat } from '@fses/ai-chat'
</script>

<template>
  <FsesAiChat api-base-url="/ai_run/api/agent" enable-chart-cards />
</template>

构建

pnpm build

产出物:

  • dist/fses-ai-chat.js:ES Module
  • dist/fses-ai-chat.umd.cjs:UMD
  • dist/style.css:样式文件
  • dist/*.d.ts:TypeScript 类型声明

测试

pnpm test