kd-chatbot-ui
# kd-chatbot-ui
Vue 3 智能体会话组件库。请求鉴权由宿主传入 request,组件库不写死 token / 拦截器。
| 模式 | 组件 | 适用场景 |
|------|------|----------|
| **适配(推荐同协议)** | AgentChatAdaptPanel | 流程与 interpret 相近:组件内调接口;地址、入参字段由宿主配置 |
| **受控(完全自定义)** | AgentChatPanel | 路径/入参/出参都可能不同:宿主自己调接口,props 传 sessions |
---
## 1. AgentChatAdaptPanel(优先阅读)
组件内部完成:拉会话列表、创建会话、发问、轮询进度、取消、写 store。
宿主只需要传:**请求函数**、**接口地址**、**传参映射**、**隔离维度**。
### 1.1 最小用法
<script setup lang="ts">
import { computed } from "vue";
import {
  AgentChatAdaptPanel,
  type AgentChatEndpoints,
  type AgentChatRequestParams
} from "kd-chatbot-ui";
import "kd-chatbot-ui/style.css";
import request from "@/utils/request";
const wellboreId = computed(() => "...");
const mainId = computed(() => "...");
const tripId = computed(() => "...");
const endpoints: AgentChatEndpoints = {
  createSession: "/ds-dynamics-alg-service/interpret/sessions",
  listSessions: "/ds-dynamics-alg-service/interpret/sessions",
  history: "/ds-dynamics-alg-service/interpret/history/:sessionId",
  ask: "/ds-dynamics-alg-service/interpret/chat/ask",
  cancel: "/ds-dynamics-alg-service/interpret/chat/cancel",
  progress: "/ds-dynamics-alg-service/interpret/chat/progress"
};
/\*\*
 \* 各接口真实传参。
 \* - 主应用字段:在闭包里直接取(wellboreId 等)
 \* - 包内字段:用参数 runtime(sessionId / taskId / content / type / since)
 \*/
const requestParams: AgentChatRequestParams = {
  createSession: () => ({
  body: {
  wellbore\_id: wellboreId.value,
  main\_id: mainId.value,
  trip\_id: tripId.value
  }
  }),
  listSessions: () => ({
  query: {
  wellbore\_id: wellboreId.value,
  main\_id: mainId.value,
  trip\_id: tripId.value
  }
  }),
  history: runtime => ({
  path: { sessionId: runtime.sessionId }
  }),
  ask: runtime => ({
  body: {
  wellbore\_id: wellboreId.value,
  main\_id: mainId.value,
  trip\_id: tripId.value,
  session\_id: runtime.sessionId,
  type: runtime.type,
  content: runtime.content
  }
  }),
  cancel: runtime => ({
  body: { task\_id: runtime.taskId }
  }),
  progress: runtime => ({
  query: {
  task\_id: runtime.taskId,
  since: runtime.since
  }
  })
};
const reloadKey = computed(
  () => `${wellboreId.value}|${mainId.value}|${tripId.value}`
);
</script>
<template>
  <AgentChatAdaptPanel
  :request="request"
  theme="dark"
  :endpoints="endpoints"
  :request-params="requestParams"
  :reload-key="reloadKey"
  :show-open-in-browser="true"
  @open-browser="handleOpenBrowser"
  />
</template>
不必再传
:context。主应用字段写在requestParams闭包里即可。
endpoints已是完整路径(以/开头)时,不必再传base-url。
### 1.2 Props
| 模板属性 | 类型 | 说明 |
|----------|------|------|
| request | AgentChatRequestFn | 宿主请求函数(带 token)。不传则用 fetch(无鉴权) |
| base-url | string | 可选统一前缀。endpoints 已给完整路径时可省略。模板写 base-url |
| endpoints | AgentChatEndpoints | 各接口路径。以 / 开头视为站点绝对路径,不再拼 base-url |
| request-params | AgentChatRequestParams | **各接口传参映射**(主应用字段 + 包内 runtime) |
| reload-key | string \\| number | 井/趟等维度变化时重拉会话。建议传 `${wellboreId}\\|${mainId}\\|${tripId}` |
| response-fields | AgentChatResponseFields | 响应字段名。默认 session\_id / task\_id / code === "OK" |
| theme | "light" \\| "dark" \\| "gray" \\| "white" | 面板主题 |
| tips | AgentChatTip\[] | 底部快捷提示(多项)。每项:value 文案、content 发送内容、type 提问类型。不传则用默认「整体分析」 |
| show-open-in-browser | boolean | 是否显示「浏览器打开」,默认 true |
| poll-interval-ms | number | 进度轮询间隔,默认 500 |
| context | AgentChatContext | **已不推荐**。仅兼容旧写法;新接入请用 request-params |
| required-context | string\[] | 仅在仍使用 context 时做必填校验 |
### 1.3 Events
| 事件 | 说明 |
|------|------|
| open-browser | 点击「浏览器打开」。其它交互(发送/切会话/取消)由面板内部处理;新开页由宿主自行 window.open |
### 1.3.1 tips 快捷提示(多项、字段均可动态)
import type { AgentChatTip } from "kd-chatbot-ui";
// 或 import { DEFAULT_AGENT_CHAT_TIPS } from "kd-chatbot-ui";
const tips: AgentChatTip[] = [
{
id: "default_analysis",
value: "整体分析", // 按钮文案
content: "请对动力学计算结果进行整体分析", // 发送内容
type: "default_analysis" // ask.type
}
// 继续追加即可,例如:
// { id: "torque", value: "扭矩分析", content: "...", type: "torque_analysis" }
];
模板::tips="tips"。点击后走与输入框相同的 ask 流程,content → runtime.content,type → runtime.type。
### 1.4 两套字段从哪里来
| 来源 | 例子 | 怎么写进请求 |
|------|------|----------------|
| **主应用** | wellboreId、mainId、tripId | 在 requestParams **闭包里直接取** |
| **包内 runtime** | sessionId、taskId、content、type、since | mapper 的参数 runtime |
runtime 由包在发请求前组装,宿主**不用**自己存 sessionId:
1. 调创建会话 / 拉列表后,包从响应里读出 session\_id(字段名可由 response-fields 改)
2. 写入包内 store:sessions\[].id + activeId
3. 用户发送时取出当前会话 id,连同 content、type 放进 runtime
4. 调用你写的 mapper,例如 session\_id: runtime.sessionId
taskId 同理:来自 ask / history 响应,用于 cancel、progress。
### 1.5 requestParams 返回结构
type AgentChatParamMapper = (
  runtime: AgentChatCallRuntime
) => {
  path?: Record<string, unknown>; // 替换 URL 里的 :name / {name}
  query?: Record<string, unknown>; // GET 查询参数
  body?: Record<string, unknown>; // POST body
};
| 接口 key | 常用写法 |
|----------|----------|
| createSession | body:主应用隔离字段 |
| listSessions | query:主应用隔离字段 |
| history | path: { sessionId: runtime.sessionId } 填 :sessionId |
| ask | body:主应用字段 + runtime.sessionId/type/content |
| cancel | body: { task\_id: runtime.taskId } |
| progress | query: { task\_id, since } |
只写需要改的接口;未写的接口仍走包内默认 interpret 字段。
### 1.6 换项目时怎么改
**只换字段名:**
ask: runtime => ({
  body: {
  wellId: wellId.value, // 你们自己的主应用字段
  chatId: runtime.sessionId, // 包内 sessionId → 你们的 chatId
  msg: runtime.content
  }
})
**路径占位也不同:**
// endpoints
history: "/xxx/history/:conversationId"
// requestParams
history: runtime => ({
  path: { conversationId: runtime.sessionId }
})
**响应字段不同:**
<AgentChatAdaptPanel
  :response-fields="{ sessionId: 'id', taskId: 'taskId', okValue: 0 }"
  ...
/>
包读出后仍放入 runtime.sessionId / runtime.taskId,后续映射不变。
### 1.7 endpoints 路径规则
- http(s)://...:原样使用
- 以 / 开头的覆盖路径:站点绝对路径,**不拼** base-url
- 其它相对路径:拼在 base-url 后面
- history 支持 :sessionId 或 {sessionId}(或你在 path 里声明的其它占位名)
### 1.8 约定接口(相对默认)
未覆盖 endpoints 时,相对 base-url:
- POST /sessions — 创建会话
- GET /sessions — 会话列表
- GET /history/:sessionId — 历史
- POST /chat/ask — 提问(返回 task\_id)
- POST /chat/cancel — 取消
- GET /chat/progress — 轮询进度
默认成功码:code === "OK"。
---
## 2. AgentChatPanel(受控模式)
宿主自己调接口,用 props 传入展示数据;用户操作通过事件抛回宿主。
### 2.1 Props / Events
| Props | 说明 |
|-------|------|
| sessions | AgentSession\[] |
| active-id | 当前会话 id |
| history-open | 历史侧栏;可用 v-model:history-open |
| is-replying | 是否回复中 |
| tips / theme / show-open-in-browser | 同适配面板 |
| Events | 说明 |
|--------|------|
| send | (payload: { text, type?, tip? }) |
| select-session | (sessionId) |
| create-session | 新建 |
| cancel-reply | 停止生成 |
| clear-session | 清空当前会话 |
| update:historyOpen | 切换历史栏 |
| open-browser | 浏览器打开 |
### 2.2 示例
<script setup>
import { ref } from "vue";
import { AgentChatPanel } from "kd-chatbot-ui";
import "kd-chatbot-ui/style.css";
const sessions = ref(\[]);
const activeId = ref("");
const historyOpen = ref(false);
const isReplying = ref(false);
async function onSend({ text, type }) {
  isReplying.value = true;
  // 调你们自己的接口,写入 sessions
  isReplying.value = false;
}
</script>
<template>
  <AgentChatPanel
  :sessions="sessions"
  :active-id="activeId"
  v-model:history-open="historyOpen"
  :is-replying="isReplying"
  @send="onSend"
  @select-session="id => (activeId = id)"
  @create-session="onCreate"
  @cancel-reply="onCancel"
  @clear-session="onClear"
  />
</template>
会话消息结构:
interface AgentSession {
  id: string;
  title: string;
  content: AgentMessage\[];
  pinned?: boolean;
  badge?: number;
  updatedAt?: number;
  snippet?: string;
}
interface AgentMessage {
  type: "ask" | "answer";
  placement: "start" | "end";
  content: string;
  segments?: { type: "reasoning" | "answer"; content: string }\[];
}
流式回复:持续更新当前会话最后一条 answer.segments,再通过 :sessions 传入即可。
---
## 3. 安装与依赖
### 3.1 安装
pnpm add kd-chatbot-ui
\# 或 npm i / yarn add
本地联调(file 依赖示例):
"kd-chatbot-ui": "file:../../agent-chat-components"
修改组件库后需在组件库目录执行 npm run build,宿主侧必要时重新 pnpm install kd-chatbot-ui。
### 3.2 Peer 依赖
| 包 | 版本参考 |
|----|----------|
| vue | ^3.5 |
| pinia | ^3 |
| element-plus | ^2.11 |
| @element-plus/icons-vue | ^2.3 |
| vue-element-plus-x | ^2 |
| echarts | ^5.5 |
| marked | ^15 / ^16 / ^18 |
| dompurify | ^3 |
### 3.3 样式
import "kd-chatbot-ui/style.css";
宿主需已安装并注册 **Pinia**(适配面板内部用包内 store)。
---
## 4. 导出一览
import {
  AgentChatAdaptPanel,
  AgentChatPanel,
  AgentChatView,
  useAgentChat,
  useAgentChatStore,
  createAgentChatClient,
  buildInterpretContext,
  INTERPRET\_POLL\_INTERVAL\_MS
} from "kd-chatbot-ui";
import type {
  AgentChatEndpoints,
  AgentChatRequestParams,
  AgentChatRequestFn,
  AgentChatCallRuntime,
  AgentChatResponseFields,
  AgentChatContext,
  AgentSession,
  AgentMessage,
  AgentChatTip,
  AgentChatSendPayload,
  AgentChatTheme
} from "kd-chatbot-ui";
---
## 5. 打包与发布
cd agent-chat-components
npm install
npm run build # 输出 dist/
发布:
npm publish # prepublishOnly 会先 build
---
## 6. 怎么选模式
- 后端仍是「会话 + ask + progress 轮询」这一套,只是路径/字段名不同 → **AgentChatAdaptPanel** + endpoints + requestParams
- 协议完全不同,或宿主已有完整编排 → **AgentChatPanel**,自己管接口与 sessions
---
## 7. 版本
- 包名:kd-chatbot-ui
- 版本:见 package.json 的 version
- License:MIT
Related Packages
Version History
| Version | Released | License |
|---|---|---|
| 0.1.1 | MIT | |
| 0.1.0 | MIT |
Pre-releases (1)
| Version | Released | License |
|---|---|---|
| 0.0.0-stage |