@blueking/chat-x 0.0.36 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ag-ui/types/contents.d.ts +2 -0
- package/dist/components/chat-content/flow-agent-content/flow-agent-node-detail.vue.d.ts +2 -0
- package/dist/composables/use-common.d.ts +1 -1
- package/dist/composables/use-custom-tab.d.ts +1 -1
- package/dist/composables/use-message-group.d.ts +6 -0
- package/dist/index.css +1 -1
- package/dist/index.js +3126 -3081
- package/dist/index.js.map +1 -1
- package/dist/lang/lang.d.ts +2 -1
- package/dist/mcp/generated/docs/activity-message.md +23 -8
- package/dist/mcp/generated/docs/chat-container.md +52 -10
- package/dist/mcp/generated/docs/file-upload-btn.md +1 -1
- package/dist/mcp/generated/docs/markdown-content.md +29 -24
- package/dist/mcp/generated/docs/message-container.md +1 -1
- package/dist/mcp/generated/docs/shortcut-render.md +2 -2
- package/dist/mcp/generated/index.json +1 -1
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/markdown-bk-inline-style.d.ts +20 -0
- package/dist/types/custom.d.ts +1 -0
- package/dist/types/input.d.ts +1 -1
- package/dist/types/tool.d.ts +2 -2
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/tokens-to-vnodes.d.ts +0 -6
- package/dist/utils/utils.d.ts +1 -0
- package/package.json +2 -2
- package/dist/utils/css-sanitizer.d.ts +0 -7
- package/dist/utils/html-sanitizer.d.ts +0 -7
package/dist/lang/lang.d.ts
CHANGED
|
@@ -96,5 +96,6 @@ export declare const lang: {
|
|
|
96
96
|
readonly '\u4F60\u597D\uFF0C\u6211\u662F\u5C0F\u9CB8': "Hello, I am BlueKing AI Bot";
|
|
97
97
|
readonly 清空搜索: "Clear Search";
|
|
98
98
|
readonly 搜索结果为空: "Search Result is Empty";
|
|
99
|
+
readonly 有效证据: "Valid Evidence";
|
|
99
100
|
};
|
|
100
|
-
export declare const t: (key: keyof typeof lang) => "Send" | "Stop" | "Ask AI" | "Copy" | "Share" | "Like" | "Unsatisfied" | "Delete" | "Quote" | "Regenerate" | "Regenerating will clear the content below" | "Submit" | "Cancel" | "Preview Content" | "Jump to Detail" | "Call Tool:" | "Calling..." | "Call Success" | "Call Failed" | "Tell us your thoughts" | "What makes you satisfied?" | "What makes you dissatisfied?" | "Return Content" | "Edit" | "Deep Thinking" | "Loading image..." | "Failed to load image" | "Thinking..." | "Thinking Completed" | "Thinking Failed" | "Copy Success" | "Copy Failed" | "Return to bottom" | "Stop generating" | "Stopping" | "Duration" | "Parameters" | "Description" | "Execution Status" | "Running" | "Success" | "Failed" | "Pending" | "To Be Executed" | "Details" | "Node" | "Node Config" | "Node Output" | "Basic Info" | "Flow Template" | "Node Name" | "Step Name" | "Execution Plan" | "Optional" | "Failure Handler" | "Timeout Control" | "Yes" | "No" | "Input Params" | "Output Params" | "Param Name" | "Param Value" | "Name" | "Structured Output" | "Manual Skip" | "No Data" | "Call MCP:" | "More" | "Searching" | "Search Completed" | "Upload File" | "Requesting..." | "Cancel satisfied" | "Cancel dissatisfied" | "Confirm delete this answer?" | "This operation cannot be undone. Please proceed with caution!" | "Preview" | "Zoom Out" | "Zoom In" | "Rotate" | "Download" | "Sorry, image loading failed. Please try reloading." | "Reset" | "Reload" | "W" | "H" | "Upload Image" | "Search keyword" | "Select date" | "Locate in Chat" | "Select All" | "Confirm" | "Upload Image, up to 3 images supported, max 2.4MB each" | "Hello, I am BlueKing AI Bot" | "Clear Search" | "Search Result is Empty" | "发送" | "停止" | "问问小鲸" | "复制" | "分享" | "点赞" | "不满意" | "删除" | "引用" | "重新生成" | "重新生成将清空下文内容" | "提交" | "取消" | "预览内容" | "跳转详情" | "调用工具:" | "调用中" | "调用成功" | "调用失败" | "说出您的想法" | "什么原因让你满意?" | "什么原因让你不满意?" | "返回内容" | "编辑" | "深度思考" | "图片加载中..." | "图片加载失败" | "思考中" | "已思考完成" | "思考失败" | "复制成功" | "复制失败" | "返回底部" | "停止生成" | "正在停止" | "耗时" | "参数" | "描述" | "执行情况" | "执行中" | "成功" | "失败" | "挂起" | "待执行" | "详情" | "节点" | "节点配置" | "节点输出" | "基础信息" | "流程模板" | "节点名称" | "步骤名称" | "执行方案" | "是否可选" | "失败处理" | "超时控制" | "是" | "否" | "输入参数" | "输出参数" | "参数名" | "参数值" | "名称" | "变量说明" | "结构化输出" | "手动跳过" | "暂无数据" | "调用 MCP:" | "更多" | "检索中" | "检索完成" | "上传文件" | "请求中..." | "取消满意" | "取消不满意" | "确认删除该回答?" | "删除操作无法撤回,请谨慎操作!" | "预览" | "缩小" | "放大" | "旋转" | "下载" | "抱歉,图片加载失败,可尝试重新加载" | "重置" | "重新加载" | "宽" | "高" | "上传图片" | "搜索 关键字" | "选择日期" | "在对话中定位" | "全选" | "确定" | "上传图片, 最多支持上传 3 个, 最大支持 2.4MB" | "你好,我是小鲸" | "清空搜索" | "搜索结果为空";
|
|
101
|
+
export declare const t: (key: keyof typeof lang) => "Send" | "Stop" | "Ask AI" | "Copy" | "Share" | "Like" | "Unsatisfied" | "Delete" | "Quote" | "Regenerate" | "Regenerating will clear the content below" | "Submit" | "Cancel" | "Preview Content" | "Jump to Detail" | "Call Tool:" | "Calling..." | "Call Success" | "Call Failed" | "Tell us your thoughts" | "What makes you satisfied?" | "What makes you dissatisfied?" | "Return Content" | "Edit" | "Deep Thinking" | "Loading image..." | "Failed to load image" | "Thinking..." | "Thinking Completed" | "Thinking Failed" | "Copy Success" | "Copy Failed" | "Return to bottom" | "Stop generating" | "Stopping" | "Duration" | "Parameters" | "Description" | "Execution Status" | "Running" | "Success" | "Failed" | "Pending" | "To Be Executed" | "Details" | "Node" | "Node Config" | "Node Output" | "Basic Info" | "Flow Template" | "Node Name" | "Step Name" | "Execution Plan" | "Optional" | "Failure Handler" | "Timeout Control" | "Yes" | "No" | "Input Params" | "Output Params" | "Param Name" | "Param Value" | "Name" | "Structured Output" | "Manual Skip" | "No Data" | "Call MCP:" | "More" | "Searching" | "Search Completed" | "Upload File" | "Requesting..." | "Cancel satisfied" | "Cancel dissatisfied" | "Confirm delete this answer?" | "This operation cannot be undone. Please proceed with caution!" | "Preview" | "Zoom Out" | "Zoom In" | "Rotate" | "Download" | "Sorry, image loading failed. Please try reloading." | "Reset" | "Reload" | "W" | "H" | "Upload Image" | "Search keyword" | "Select date" | "Locate in Chat" | "Select All" | "Confirm" | "Upload Image, up to 3 images supported, max 2.4MB each" | "Hello, I am BlueKing AI Bot" | "Clear Search" | "Search Result is Empty" | "Valid Evidence" | "发送" | "停止" | "问问小鲸" | "复制" | "分享" | "点赞" | "不满意" | "删除" | "引用" | "重新生成" | "重新生成将清空下文内容" | "提交" | "取消" | "预览内容" | "跳转详情" | "调用工具:" | "调用中" | "调用成功" | "调用失败" | "说出您的想法" | "什么原因让你满意?" | "什么原因让你不满意?" | "返回内容" | "编辑" | "深度思考" | "图片加载中..." | "图片加载失败" | "思考中" | "已思考完成" | "思考失败" | "复制成功" | "复制失败" | "返回底部" | "停止生成" | "正在停止" | "耗时" | "参数" | "描述" | "执行情况" | "执行中" | "成功" | "失败" | "挂起" | "待执行" | "详情" | "节点" | "节点配置" | "节点输出" | "基础信息" | "流程模板" | "节点名称" | "步骤名称" | "执行方案" | "是否可选" | "失败处理" | "超时控制" | "是" | "否" | "输入参数" | "输出参数" | "参数名" | "参数值" | "名称" | "变量说明" | "结构化输出" | "手动跳过" | "暂无数据" | "调用 MCP:" | "更多" | "检索中" | "检索完成" | "上传文件" | "请求中..." | "取消满意" | "取消不满意" | "确认删除该回答?" | "删除操作无法撤回,请谨慎操作!" | "预览" | "缩小" | "放大" | "旋转" | "下载" | "抱歉,图片加载失败,可尝试重新加载" | "重置" | "重新加载" | "宽" | "高" | "上传图片" | "搜索 关键字" | "选择日期" | "在对话中定位" | "全选" | "确定" | "上传图片, 最多支持上传 3 个, 最大支持 2.4MB" | "你好,我是小鲸" | "清空搜索" | "搜索结果为空" | "有效证据";
|
|
@@ -156,11 +156,14 @@ ActivityMessage 展示活动类消息:知识检索(knowledge_rag)、引用
|
|
|
156
156
|
### 核心交互
|
|
157
157
|
|
|
158
158
|
- **标题栏**:显示「执行情况」+ 所有任务聚合后的各状态计数(执行中 / 成功 / 失败 / 挂起),颜色区分
|
|
159
|
-
-
|
|
159
|
+
- **任务组**:逐个展示任务行,带状态图标、总耗时;点击箭头图标可折叠/展开节点列表
|
|
160
|
+
- **有效证据**:`task.has_confidence === true` 时,任务行右侧展示「有效证据」按钮,点击后在侧栏打开置信度/证据详情 Tab(`props.has_confidence: true`)
|
|
161
|
+
- **默认激活**:当 `MessageContainer` 已注入滚动上下文(`useContainerScrollProvider`,供 `FlowAgentContent` 内 `useContainerScrollConsumer` 读取)时,组件挂载后若存在 `task.is_active === true` 且 `task.has_confidence === true` 的任务,会自动在侧栏打开该任务的「有效证据」Tab;无滚动 Provider(例如独立演示)时不做自动打开。用户手动切换 Tab 后不再沿用 `is_active` 默认高亮
|
|
162
|
+
- **选中态**:当前侧栏 Tab 与任务行 / 节点行联动高亮(`is-selected`);任务 Tab 与「有效证据」Tab 均视为该任务的选中态
|
|
160
163
|
- **节点列表**:每个节点显示状态圆点、名称和耗时;hover 时出现「详情」按钮
|
|
161
|
-
-
|
|
164
|
+
- **节点详情**:点击「详情」会通过 `useCustomTabConsumer` 在 `ChatContainer` 侧边栏新增自定义 Tab,展示节点配置(基础信息、输入参数、输出参数)
|
|
162
165
|
|
|
163
|
-
> `FlowAgentContent` 会读取 `ChatContainer` 注入的 `renderMode`。当 `renderMode === RenderMode.Share`
|
|
166
|
+
> `FlowAgentContent` 会读取 `ChatContainer` 注入的 `renderMode`。当 `renderMode === RenderMode.Share` 时,任务行不展示总耗时与「有效证据」,节点列表不展示耗时与「详情」按钮,避免分享预览中出现可交互入口。独立使用 `ActivityMessage` 且没有上层 Provider 时,默认按 `Chat` 模式渲染。
|
|
164
167
|
|
|
165
168
|
### 内部渲染结构
|
|
166
169
|
|
|
@@ -172,16 +175,16 @@ FlowAgentContent(activityType = 'flow_agent')
|
|
|
172
175
|
│ └── 执行情况:执行中 N / 成功 N / 失败 N / 挂起 N
|
|
173
176
|
└── #default
|
|
174
177
|
└── TaskGroup × N
|
|
175
|
-
├── TaskHeader
|
|
178
|
+
├── TaskHeader(is-selected / has-confidence;箭头点击折叠)
|
|
176
179
|
│ ├── 状态图标(running=Loading / success / failed / suspended)
|
|
177
180
|
│ ├── task_name(HighlightKeyword 支持搜索高亮)
|
|
178
|
-
│ └──
|
|
181
|
+
│ └── trailing:总耗时 + 「有效证据」(has_confidence 时)
|
|
179
182
|
└── NodeList
|
|
180
|
-
└── NodeItem × N
|
|
183
|
+
└── NodeItem × N(is-selected 与侧栏 Tab 联动)
|
|
181
184
|
├── 状态圆点(颜色对应状态)
|
|
182
185
|
├── node.name(HighlightKeyword 支持搜索高亮)
|
|
183
186
|
├── node.elapsed_time
|
|
184
|
-
└── 详情按钮(hover 显示)→
|
|
187
|
+
└── 详情按钮(hover 显示)→ 打开节点详情 Tab
|
|
185
188
|
```
|
|
186
189
|
|
|
187
190
|
### 用法示例
|
|
@@ -294,9 +297,19 @@ const messages = [
|
|
|
294
297
|
| `suspended` | SUSPENDED | #F59500 |
|
|
295
298
|
| `pending` | PENDING | #DCDEE5 |
|
|
296
299
|
|
|
300
|
+
### 侧栏 Tab 命名规则
|
|
301
|
+
|
|
302
|
+
| 场景 | `tab.name` 格式 |
|
|
303
|
+
| ---------- | ---------------------------------------- |
|
|
304
|
+
| 任务详情 | `{task_id}` |
|
|
305
|
+
| 有效证据 | `{task_id}`(与任务 Tab 同名,label 为「有效证据」) |
|
|
306
|
+
| 节点详情 | `{task_id}\|{node.id}\|{node.name}` |
|
|
307
|
+
|
|
308
|
+
`CustomBkFlowTabData` 支持 `has_confidence?: boolean`,用于侧栏详情组件区分证据视图与节点视图。应用层可通过 `ChatContainer` 的 `getSideRenderComponent` 覆盖渲染组件。
|
|
309
|
+
|
|
297
310
|
### 节点详情 Tab
|
|
298
311
|
|
|
299
|
-
点击节点的「详情」按钮,内部调用 `useCustomTabConsumer().addCustomTab()` 在 `ChatContainer` 侧边栏新开一个 Tab,渲染 `
|
|
312
|
+
点击节点的「详情」按钮,内部调用 `useCustomTabConsumer().addCustomTab()` 在 `ChatContainer` 侧边栏新开一个 Tab,渲染 `BkFlowNodeDetail`(或 `getSideRenderComponent` 返回的自定义组件),该组件提供:
|
|
300
313
|
|
|
301
314
|
- **节点配置** Tab:基础信息表单(流程模板、节点名称、步骤名称、失败处理、超时控制)+ 输入参数表 + 输出参数表
|
|
302
315
|
- **节点输出** Tab:结构化输出参数表
|
|
@@ -310,6 +323,8 @@ import { MessageContentType, type BkFlowMessageContent, type BkFlowNode, type Bk
|
|
|
310
323
|
type BkFlowMessageContent = BkFlowTask[];
|
|
311
324
|
|
|
312
325
|
type BkFlowTask = {
|
|
326
|
+
has_confidence?: boolean; // 是否展示「有效证据」入口;与 is_active 同时为 true 且在消息容器滚动上下文中时,挂载后自动打开「有效证据」侧栏 Tab
|
|
327
|
+
is_active?: boolean; // 是否默认激活;需配合 has_confidence 且存在滚动 Provider 才会自动打开侧栏「有效证据」Tab
|
|
313
328
|
nodes: Record<string, BkFlowNode>;
|
|
314
329
|
statistics: { state_counts: Record<string, number>; total: number };
|
|
315
330
|
task_id: number;
|
|
@@ -21,7 +21,7 @@ ChatContainer 提供完整 AI 对话布局:分栏(ResizeLayout)、消息
|
|
|
21
21
|
|
|
22
22
|
## 核心能力
|
|
23
23
|
|
|
24
|
-
- **分栏布局**:基于 `ResizeLayout` 的可拖拽分栏;**侧栏是否展示 Tab / 执行摘要、以及分栏是否进入折叠样式(`ai-is-collapse`)以 `executionGroups`
|
|
24
|
+
- **分栏布局**:基于 `ResizeLayout` 的可拖拽分栏;**侧栏是否展示 Tab / 执行摘要、以及分栏是否进入折叠样式(`ai-is-collapse`)以 `executionGroups` 与执行情况搜索关键词 `keyword` 共同决定**(`executionGroups` 由 `useMessageGroup` 从消息中过滤工具调用与 FlowAgent 记录;`keyword` 来自 `ExecutionSummary` 的 `@update-keyword`)。当 `executionGroups` 为空且未输入搜索词时,侧栏 Tab 与执行摘要不展示;**用户正在搜索执行情况时(`keyword` 非空),即使暂无执行类消息也会保留侧栏**,避免搜索态被折叠
|
|
25
25
|
- **消息分组**:内置 `useMessageGroup` 自动处理消息分组、Tool 合并、Loading 注入
|
|
26
26
|
- **输入区状态推导**:传给 `MessageContainer` 与 `ChatInput` 的 `messageStatus` 为内部计算值 `inputStatus`:当分组中存在 id 为 `LOADING_MESSAGE_ID`(`'__loading__'`,由 `useMessageGroup` 注入的占位 Loading 消息)时,对内使用 `MessageStatus.Fetching`;否则使用外部传入的 `messageStatus`。用于在「已发用户消息、尚未流式」阶段与流式中一致地展示停止能力,并避免输入区重复发送
|
|
27
27
|
- **执行摘要**:侧边栏展示工具调用 / FlowAgent 执行记录,支持关键词搜索和对话定位
|
|
@@ -39,9 +39,9 @@ ai-chat-container
|
|
|
39
39
|
├── aside(侧边栏)
|
|
40
40
|
│ ├── Tab 标签页
|
|
41
41
|
│ │ ├── 执行情况(默认 Tab)
|
|
42
|
-
│ │ └── 自定义 Tab × N
|
|
42
|
+
│ │ └── 自定义 Tab × N(可关闭;标签可由 `getSideTabRenderComponent` 自定义)
|
|
43
43
|
│ ├── ExecutionSummary(执行情况 Tab 内容)
|
|
44
|
-
│ ├── 自定义 Tab
|
|
44
|
+
│ ├── 自定义 Tab 组件(`getSideRenderComponent` 优先,否则 `data.component`;可向子组件注入 #locateButton)
|
|
45
45
|
│ └── collapse-button(折叠按钮)
|
|
46
46
|
└── main(主内容区)
|
|
47
47
|
├── MessageContainer(有消息时)
|
|
@@ -109,9 +109,9 @@ ai-chat-container
|
|
|
109
109
|
|
|
110
110
|
侧边栏默认包含「执行情况」Tab,展示所有工具调用和 FlowAgent 类型的 Activity 消息。支持关键词搜索过滤和点击定位到对话中的消息位置。
|
|
111
111
|
|
|
112
|
-
**展示条件**:当 `executionGroups` 为空时,不渲染侧栏 Tab 与 `ExecutionSummary`(折叠按钮亦隐藏);主区域仍可正常展示 `messages`
|
|
112
|
+
**展示条件**:当 `executionGroups` 为空且 `keyword` 为空时,不渲染侧栏 Tab 与 `ExecutionSummary`(折叠按钮亦隐藏);主区域仍可正常展示 `messages` 中的对话内容。用户在执行情况中输入搜索词后,侧栏会保持展示以显示「搜索结果为空」等状态。`renderMode === Share` 时侧栏隐藏,且分栏会应用与折叠一致的样式。
|
|
113
113
|
|
|
114
|
-
**自定义 Tab 联动**:当 `executionGroups`
|
|
114
|
+
**自定义 Tab 联动**:当 `executionGroups` 变为空且搜索词已清空时,容器会**自动重置自定义 Tab**(`resetCustomTab`),避免残留节点详情等 Tab;若用户仍在搜索(`keyword` 非空),不会触发重置。
|
|
115
115
|
|
|
116
116
|
```vue
|
|
117
117
|
<template>
|
|
@@ -147,11 +147,51 @@ ai-chat-container
|
|
|
147
147
|
|
|
148
148
|
## 自定义 Tab
|
|
149
149
|
|
|
150
|
-
通过 `ref` 获取组件实例后,使用 `addCustomTab` / `removeCustomTab` 动态管理侧边栏 Tab。若 **`executionGroups`
|
|
150
|
+
通过 `ref` 获取组件实例后,使用 `addCustomTab` / `removeCustomTab` 动态管理侧边栏 Tab。若 **`executionGroups` 变为空且搜索词已清空**,容器会清空自定义 Tab 状态(与侧栏执行数据联动,见上文「侧边栏与执行摘要」)。
|
|
151
|
+
|
|
152
|
+
### 侧栏渲染扩展
|
|
153
|
+
|
|
154
|
+
应用层可通过以下 Props 覆盖默认 Tab 标签与侧栏内容区的渲染逻辑(例如 FlowAgent 节点详情使用业务自定义组件):
|
|
155
|
+
|
|
156
|
+
| Prop | 说明 |
|
|
157
|
+
| ---- | ---- |
|
|
158
|
+
| `getSideTabRenderComponent` | `(h, tab, { removeCustomTab }) => VNode \| undefined`。返回自定义 Tab 标签 VNode;未返回时使用默认图标 + `tab.label` + 关闭按钮 |
|
|
159
|
+
| `getSideRenderComponent` | `(h, props) => VNode \| undefined`。返回侧栏内容区组件 VNode;未返回时使用 `selectedTab.data.component` |
|
|
160
|
+
|
|
161
|
+
侧栏内容区实现上会以 **`selectedTab.name` 作为外层 `key`**,切换 Tab 时重建子树,避免插槽与局部状态残留;当前 Tab 的 `:is` 由内部 **`computed`** 根据 `getSideRenderComponent(h, selectedTab.data.props)` 与 `data.component` 解析,保证 Tab 切换或 `onCustomTabChange` 异步更新 props 后内容类型与数据一致。
|
|
162
|
+
|
|
163
|
+
```vue
|
|
164
|
+
<template>
|
|
165
|
+
<ChatContainer
|
|
166
|
+
:get-side-tab-render-component="renderSideTab"
|
|
167
|
+
:get-side-render-component="renderSidePanel"
|
|
168
|
+
...
|
|
169
|
+
/>
|
|
170
|
+
</template>
|
|
171
|
+
|
|
172
|
+
<script setup lang="ts">
|
|
173
|
+
import { h } from 'vue';
|
|
174
|
+
import type { CustomTab } from '@blueking/chat-x';
|
|
175
|
+
|
|
176
|
+
const renderSideTab = (createElement, tab, { removeCustomTab }) => {
|
|
177
|
+
if (tab.name.startsWith('custom-')) {
|
|
178
|
+
return createElement('span', {}, tab.label);
|
|
179
|
+
}
|
|
180
|
+
return undefined; // 走默认 Tab 标签
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const renderSidePanel = (createElement, props) => {
|
|
184
|
+
if (props?.has_confidence) {
|
|
185
|
+
return createElement(MyConfidencePanel, props);
|
|
186
|
+
}
|
|
187
|
+
return undefined; // 走 tab.data.component
|
|
188
|
+
};
|
|
189
|
+
</script>
|
|
190
|
+
```
|
|
151
191
|
|
|
152
192
|
### 自定义 Tab 与「在对话中定位」
|
|
153
193
|
|
|
154
|
-
`addCustomTab` 的 `data` 可携带 **`messageUid`**(与对应活动消息的 `message.uid` 一致)。`ChatContainer` 在侧栏用 `<component :is
|
|
194
|
+
`addCustomTab` 的 `data` 可携带 **`messageUid`**(与对应活动消息的 `message.uid` 一致)。`ChatContainer` 在侧栏用 `<component :is="sideRenderComponent">`(内部计算属性,见上文「侧栏渲染扩展」)渲染自定义 Tab 时,会向子组件提供 **`locateButton` 插槽**:默认渲染「在对话中定位」按钮,点击后调用内部 `handleLocateMessageGroup(messageUid)`,优先滚动到主区域 `document.getElementById(messageUid)`;若不存在该节点,则在当前 `messageGroups` 中查找包含 `message.uid === messageUid` 的消息组,并滚动到该组的容器(`MessageGroup.uid` 作为组级 `id`)。
|
|
155
195
|
|
|
156
196
|
子组件若需展示该按钮,请在模板中声明 `<slot name="locateButton" />`(例如 FlowAgent 节点详情标题栏)。`FlowAgentContent` 等会在打开节点详情 Tab 时将 `messageUid` 写入 `data`,与 `ActivityMessage` 下传给内容区的 `message-uid` 对齐。
|
|
157
197
|
|
|
@@ -339,9 +379,11 @@ ChatContainer 的 Props 继承自 `ChatInputProps` 和 `MessageContainerProps`
|
|
|
339
379
|
|
|
340
380
|
| 属性名 | 类型 | 默认值 | 说明 |
|
|
341
381
|
| ------------------ | ---------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
342
|
-
| chatLoading
|
|
343
|
-
| commonTippyOptions
|
|
344
|
-
|
|
|
382
|
+
| chatLoading | `boolean` | — | 整体加载状态,`true` 时显示 Loading 遮罩 |
|
|
383
|
+
| commonTippyOptions | `AITippyProps` | — | 通用 Tippy 配置(`appendTo` / `placement` / `zIndex`),传入的选项会注入到所有使用 `v-overflow-tips` 的子组件中 |
|
|
384
|
+
| getSideRenderComponent | `(h, props?) => VNode \| undefined` | — | 自定义侧栏内容区渲染;未返回时使用 `selectedTab.data.component` |
|
|
385
|
+
| getSideTabRenderComponent | `(h, tab, { removeCustomTab }) => VNode \| undefined` | — | 自定义侧栏 Tab 标签渲染;未返回时使用默认图标 + 文案 + 关闭按钮 |
|
|
386
|
+
| openingRemark | `string` | — | 开场白,无消息时显示,支持 Markdown |
|
|
345
387
|
| placement | `'left' \| 'right'` | `'left'` | 侧边栏位置 |
|
|
346
388
|
| resizeProps | `{ disabled?: boolean; initialDivide?: number \| string; max?: number; min?: number }` | — | 透传给内部 `ResizeLayout` 的可选配置,与默认 `collapsible: false`、`immediate: true`、`min: 400` 合并;`placement` 始终取自本组件 `placement`;`initialDivide` 可为像素数字或百分比等字符串(与 bkui ResizeLayout 一致) |
|
|
347
389
|
| onCustomTabChange | `(tab: CustomTab) => Promise<any>` | — | 自定义 Tab 切换回调,返回值作为 Tab 组件 props |
|
|
@@ -149,7 +149,7 @@ FileUploadBtn 提供隐藏 file input 与图标按钮,选择后在按钮层过
|
|
|
149
149
|
```typescript
|
|
150
150
|
import type { TippyOptions } from 'vue-tippy';
|
|
151
151
|
|
|
152
|
-
type AITippyProps = Partial<
|
|
152
|
+
type AITippyProps = Partial<Pick<TippyOptions, 'appendTo' | 'placement' | 'zIndex'>>;
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
## 关联组件
|
|
@@ -23,8 +23,8 @@ AI 消息内容渲染的核心原子组件,集成代码高亮、LaTeX 公式
|
|
|
23
23
|
## 组件结构与渲染流程
|
|
24
24
|
|
|
25
25
|
```
|
|
26
|
-
props.content → completeMarkdownSyntax → md.parse
|
|
27
|
-
|
|
26
|
+
props.content → completeMarkdownSyntax → md.parse → groupTokens → groupedTokens
|
|
27
|
+
│
|
|
28
28
|
div.ai-markdown-content(contain: layout style)
|
|
29
29
|
│
|
|
30
30
|
status === 'error' → CommonErrorContent(:content)
|
|
@@ -39,21 +39,12 @@ props.content → completeMarkdownSyntax → md.parse(html: true)→ groupTo
|
|
|
39
39
|
↓ ↓ ↓ ↓
|
|
40
40
|
MermaidContent LatexContent CodeContent VNodeRenderer
|
|
41
41
|
@mounted @mounted @mounted @vue:mounted
|
|
42
|
-
│
|
|
43
|
-
└──── handleTokenMounted(throttle 100ms
|
|
44
|
-
→ containerScroll.toScrollBottom() │
|
|
45
|
-
sanitize(DOMPurify + sanitizeCSS)
|
|
46
|
-
sanitizeHtmlFragment(流式片段净化)
|
|
42
|
+
│
|
|
43
|
+
└──── handleTokenMounted(throttle 100ms)→ containerScroll.toScrollBottom()
|
|
47
44
|
```
|
|
48
45
|
|
|
49
46
|
`VNodeRenderer` 的 `options` 中包含与当前 `MarkdownIt` 实例一致的 `mditOptions`(即 `md.options`),以便 `tokensToVNodes` 调用 `renderer.rules` 时第三参与 markdown-it 原生规则签名一致。
|
|
50
47
|
|
|
51
|
-
`MarkdownIt` 构造时开启 `html: true`,允许行内 HTML 标签(如 `<font>`、`<div>`)通过 markdown-it 解析为 `html_inline` / `html_block` token。
|
|
52
|
-
|
|
53
|
-
两组净化函数各司其职:
|
|
54
|
-
- `sanitize`:DOMPurify 全局过滤后,再对 `style` 属性值进行 CSS 属性白名单校验(`sanitizeCSS`),用于最终渲染的完整 HTML。
|
|
55
|
-
- `sanitizeHtmlFragment`:轻量级片段净化,**不自动闭合标签**,专用于流式渲染中拆分到多个 token 的 HTML 标签场景。
|
|
56
|
-
|
|
57
48
|
### Token 分组(groupTokens)
|
|
58
49
|
|
|
59
50
|
`groupTokens` 使用栈将扁平 Token 数组转为分组数组,每组对应一个顶层 DOM 节点(段落、标题、列表、代码块等):
|
|
@@ -186,6 +177,7 @@ props.content → completeMarkdownSyntax → md.parse(html: true)→ groupTo
|
|
|
186
177
|
|
|
187
178
|
| 插件 | 语法 | 功能 |
|
|
188
179
|
| --------------------------- | ------------------- | -------------------- |
|
|
180
|
+
| `markdownItBkInlineStyle` | 见下文「蓝鲸行内样式」 | 安全行内颜色/字号/粗斜体(非 HTML) |
|
|
189
181
|
| `markdown-it-footnote` | `[^1]` | 脚注 |
|
|
190
182
|
| `markdown-it-ins` | `++text++` | 下划线 |
|
|
191
183
|
| `markdown-it-mark` | `==text==` | 高亮 |
|
|
@@ -196,26 +188,39 @@ props.content → completeMarkdownSyntax → md.parse(html: true)→ groupTo
|
|
|
196
188
|
| `markdownItLatex` | `$...$` / `$$...$$` | KaTeX 数学公式 token |
|
|
197
189
|
| `markdownItContainer` | `::: hljs-left` 等 | 自定义对齐容器(class 与 highlight.js 命名对齐) |
|
|
198
190
|
|
|
191
|
+
### 蓝鲸行内样式(`markdownItBkInlineStyle`)
|
|
192
|
+
|
|
193
|
+
不开启 `html: true`,由专用语法生成带白名单 `style` 的 `<span class="bk-md-inline-style">`。
|
|
194
|
+
|
|
195
|
+
**语法**:`::bk{` *属性* `}` *正文* `:/bk::`
|
|
196
|
+
|
|
197
|
+
- 属性写在 `{}` 内,使用 `;` 分隔;每项为 `键=值` 或 `键:值`。
|
|
198
|
+
- 正文支持行内 Markdown(如 `**粗体**`)。
|
|
199
|
+
- 结束标记必须为字面量 `:/bk::`,请勿在正文中出现该序列。
|
|
200
|
+
|
|
201
|
+
**支持的键**:`color` / `c`、`background-color`、`font-size`、`bold`、`italic`(详见 `plugins/markdown-bk-inline-style.ts` 内注释)。
|
|
202
|
+
|
|
203
|
+
**示例**:
|
|
204
|
+
|
|
205
|
+
```markdown
|
|
206
|
+
::bk{color:#c00;font-size:18px}**重要**:/bk::
|
|
207
|
+
::bk{background-color:yellow}高亮:/bk::
|
|
208
|
+
::bk{bold;italic}强调:/bk::
|
|
209
|
+
```
|
|
210
|
+
|
|
199
211
|
### 安全性
|
|
200
212
|
|
|
201
|
-
HTML
|
|
213
|
+
`MarkdownIt` **不**开启 `html: true`,用户无法插入任意 HTML 标签;行内彩色/字号等请使用上文「蓝鲸行内样式」扩展。
|
|
202
214
|
|
|
203
|
-
|
|
215
|
+
`VNodeRenderer` 渲染的 HTML 统一经过 DOMPurify 过滤,并额外允许 KaTeX 所需标签:
|
|
204
216
|
|
|
205
217
|
```typescript
|
|
206
218
|
const domPurifyConfig = {
|
|
207
|
-
ADD_TAGS: ['
|
|
208
|
-
ADD_ATTR: ['xmlns', 'mathvariant', 'encoding', 'style'
|
|
209
|
-
FORBID_TAGS: ['style'],
|
|
219
|
+
ADD_TAGS: ['semantics', 'mrow', 'mi', 'mo', 'mn', 'msup', 'msub', 'mfrac', 'mtext', 'annotation'],
|
|
220
|
+
ADD_ATTR: ['xmlns', 'mathvariant', 'encoding', 'style'],
|
|
210
221
|
};
|
|
211
222
|
```
|
|
212
223
|
|
|
213
|
-
> `FORBID_TAGS: ['style']` 防止 `<style>` 标签注入全局 CSS,样式属性通过 `style` 属性(attribute)而非 `<style>` 标签(tag)控制。
|
|
214
|
-
|
|
215
|
-
**第二层 — CSS 属性白名单**(`sanitizeCSS`):DOMPurify 处理后,对 `style` 属性值做二次过滤,仅保留白名单内的安全 CSS 属性,拦截 `url()`、`expression()`、`javascript:` 等危险模式。
|
|
216
|
-
|
|
217
|
-
**流式场景 — `sanitizeHtmlFragment`**:流式渲染中 HTML 标签可能被拆分到多个 `html_inline` token(如 `<font color="red">` 和 `</font>` 分属不同 token),DOMPurify 会自动闭合未匹配标签导致样式丢失。`sanitizeHtmlFragment` 只做危险模式匹配不自动闭合,专用于此场景。
|
|
218
|
-
|
|
219
224
|
> `CodeContent`、`MermaidContent`、`LatexContent` 各自内部处理安全性(KaTeX `errorColor`、highlight.js 转义等),不经过 DOMPurify。
|
|
220
225
|
|
|
221
226
|
## 关联组件
|
|
@@ -461,7 +461,7 @@ AI 回复状态为 `error` 时,消息以错误样式展示:
|
|
|
461
461
|
| messageGroups | `MessageGroup[]` | — | 预计算的消息分组;传入时跳过内部分组逻辑,由 `ChatContainer` 通过 `useMessageGroup` 提供 |
|
|
462
462
|
| messageStatus | `MessageStatus` | — | 当前整体消息状态,控制底部「停止生成」按钮显示;`ChatContainer` 会结合末尾 Loading 占位推导 `fetching` 等再传入 |
|
|
463
463
|
| messageToolsStatus | `MessageToolsStatus` | — | 工具栏状态,透传给 `MessageTools` 和 `MessageRender` |
|
|
464
|
-
| messageToolsTippyOptions | `AITippyProps` | — | 透传给 `MessageTools` 和 `MessageRender`(进而透传给 `UserMessage` 的工具栏)的 Tippy 配置,用于自定义 tooltip
|
|
464
|
+
| messageToolsTippyOptions | `AITippyProps` | — | 透传给 `MessageTools` 和 `MessageRender`(进而透传给 `UserMessage` 的工具栏)的 Tippy 配置,用于自定义 tooltip 挂载点、位置等(如 `appendTo`、`placement`、`zIndex`) |
|
|
465
465
|
| enableSelection | `boolean` | `false` | 是否启用多选模式 |
|
|
466
466
|
| onAgentAction | `(tool: IToolBtn, messages: Message[]) => Promise<string[] \| void>` | — | AI 消息工具操作回调;`copy` 操作由内部处理,`like/unlike` 应返回反馈原因字符串数组 |
|
|
467
467
|
| onAgentFeedback | `(tool: IToolBtn, messages: Message[], reasonList: string[], otherReason: string) => void` | — | AI 消息反馈提交回调(点赞/踩选完原因后触发) |
|
|
@@ -344,7 +344,7 @@ const components: ShortcutComponent[] = [
|
|
|
344
344
|
| ------------- | ------------------------------------ | ---- | ------------------------------------------------------------------------------------------ |
|
|
345
345
|
| type | 见[表单类型](#表单组件类型) | ✓ | 控件类型;未知类型返回 `null`,不渲染 |
|
|
346
346
|
| key | `string` | ✓ | 表单字段名;`submit` 事件返回对象以此为 key;同时作为校验 property |
|
|
347
|
-
| name | `string` | — |
|
|
347
|
+
| name | `string` | — | 表单项标签;优先于 `formItemProps.label`,通过 `#label` 插槽渲染为 `.shortcut-render-form-label` |
|
|
348
348
|
| default | `string` | — | 字段初始值;优先于 `formModel`,在 `watchEffect` 中覆盖写入 |
|
|
349
349
|
| fillBack | `boolean` | — | `true` 时映射为 `required: true`(必填校验),同时标记回填语义 |
|
|
350
350
|
| placeholder | `string` | — | 占位文本(`input` / `textarea` / `number` 可用) |
|
|
@@ -413,7 +413,7 @@ interface BaseShortcutComponent {
|
|
|
413
413
|
|
|
414
414
|
## 样式说明
|
|
415
415
|
|
|
416
|
-
|
|
416
|
+
表单项与控件会附加类型化 class,便于样式覆盖:`shortcut-render-form-item_{type}`(如 `_radio`、`_checkbox`),单选/多选项子项为 `shortcut-render-form-item_radio` / `shortcut-render-form-item_checkbox`。表单项标签使用 BEM 风格类名 `shortcut-render-form-label`。
|
|
417
417
|
|
|
418
418
|
## 关联组件
|
|
419
419
|
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 蓝鲸行内富文本(安全样式)扩展。
|
|
3
|
+
*
|
|
4
|
+
* 语法(与 HTML 无关,不开启 markdown-it `html`):
|
|
5
|
+
*
|
|
6
|
+
* ::bk{ 属性列表 } 正文内容 :/bk::
|
|
7
|
+
*
|
|
8
|
+
* - 属性列表:写在 `{}` 内,使用 `;` 分隔,每项为 `键=值` 或 `键:值`(等号与冒号等价)。
|
|
9
|
+
* - 正文:支持行内 Markdown(加粗、链接、行内代码等),由 markdown-it 再次 tokenize。
|
|
10
|
+
* - 结束标记固定为 `:/bk::`,请勿在正文中使用该字面量。
|
|
11
|
+
*
|
|
12
|
+
* 支持的键(仅生成固定白名单 style):
|
|
13
|
+
* - `color` / `c`:颜色(#rgb / #rrggbb 或 CSS 命名色)
|
|
14
|
+
* - `background-color`:背景色,规则同 color
|
|
15
|
+
* - `font-size`:字号,如 `14px`(限制 1-72px)
|
|
16
|
+
* - `bold`:加粗
|
|
17
|
+
* - `italic`:斜体
|
|
18
|
+
*/
|
|
19
|
+
import type { PluginSimple } from '../markdown-it';
|
|
20
|
+
export declare const markdownItBkInlineStyle: PluginSimple;
|
package/dist/types/custom.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Component } from 'vue';
|
|
|
2
2
|
export type CustomBkFlowTab = CustomTab<CustomBkFlowTabData>;
|
|
3
3
|
export type CustomBkFlowTabData = CustomTabData<{
|
|
4
4
|
data?: Partial<NodeDetailData>;
|
|
5
|
+
has_confidence?: boolean;
|
|
5
6
|
loading?: boolean;
|
|
6
7
|
node_id?: string;
|
|
7
8
|
node_name?: string;
|
package/dist/types/input.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type tagSchema } from '../components/chat-input/ai-slash-input/constants';
|
|
2
1
|
import type { BinaryInputContent } from '../ag-ui/types/contents';
|
|
2
|
+
import type { tagSchema } from '../components/chat-input/ai-slash-input/constants';
|
|
3
3
|
import type { InferDoc } from '../edix';
|
|
4
4
|
export declare const MessageState: {
|
|
5
5
|
readonly ACTIVE: "active";
|
package/dist/types/tool.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ToolIconsMap } from '../icons/tools';
|
|
2
2
|
import type { TippyOptions } from 'vue-tippy';
|
|
3
3
|
export declare enum MessageToolsStatus {
|
|
4
4
|
Disabled = "disabled",// 禁用
|
|
5
5
|
Hidden = "hidden"
|
|
6
6
|
}
|
|
7
|
-
export type AITippyProps = Partial<Pick<TippyOptions, 'appendTo' | 'zIndex'>>;
|
|
7
|
+
export type AITippyProps = Partial<Pick<TippyOptions, 'appendTo' | 'placement' | 'zIndex'>>;
|
|
8
8
|
export interface IToolBtn {
|
|
9
9
|
description?: string;
|
|
10
10
|
id: keyof typeof ToolIconsMap;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -17,12 +17,6 @@ export interface TokenToVNodeOptions {
|
|
|
17
17
|
* HTML 净化函数,用于处理 innerHTML 的内容
|
|
18
18
|
*/
|
|
19
19
|
sanitize?: (html: string) => string;
|
|
20
|
-
/**
|
|
21
|
-
* HTML 片段净化函数,用于流式场景下 html_inline/html_block token 的净化。
|
|
22
|
-
* 与 sanitize 不同,此函数不会自动闭合未匹配的标签,
|
|
23
|
-
* 因为流式渲染中 HTML 标签可能被拆分到不同的 token 中。
|
|
24
|
-
*/
|
|
25
|
-
sanitizeHtmlFragment?: (html: string) => string;
|
|
26
20
|
}
|
|
27
21
|
type TokenAttrs = [string, string][];
|
|
28
22
|
/**
|
package/dist/utils/utils.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blueking/chat-x",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
4
4
|
"description": "蓝鲸智云 AI Chat 组件库 —— 遵循 AG-UI,为 AI Agent 和人类开发者共同设计的对话 UI 组件库。",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"vitepress": "2.0.0-alpha.16",
|
|
79
79
|
"vitest": "^4.0.18",
|
|
80
80
|
"vue-tsc": "^3.1.4",
|
|
81
|
-
"@blueking/chat-helper": "0.0.
|
|
81
|
+
"@blueking/chat-helper": "0.0.5"
|
|
82
82
|
},
|
|
83
83
|
"scripts": {
|
|
84
84
|
"dev": "vite --config vite.config.ts",
|