@blueking/chat-x 0.0.50 → 0.0.51-beta.1

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.
Files changed (54) hide show
  1. package/dist/ag-ui/types/contents.d.ts +2 -0
  2. package/dist/ag-ui/types/messages.d.ts +5 -0
  3. package/dist/common/constants.d.ts +1 -1
  4. package/dist/components/ai-buttons/file-upload-btn/file-upload-btn.vue.d.ts +0 -2
  5. package/dist/components/chat-content/file-content/file-content.vue.d.ts +5 -2
  6. package/dist/components/chat-content/file-content/upload-file-item.vue.d.ts +12 -0
  7. package/dist/components/chat-content/file-content/upload-image-item.vue.d.ts +21 -0
  8. package/dist/components/chat-input/ai-slash-editor/ai-slash-editor.vue.d.ts +1 -1
  9. package/dist/components/chat-input/build-default-placeholder.d.ts +7 -0
  10. package/dist/components/chat-input/chat-input.vue.d.ts +1 -1
  11. package/dist/components/chat-message/message-container/message-container.vue.d.ts +1 -0
  12. package/dist/components/chat-message/message-render/message-render.vue.d.ts +2 -0
  13. package/dist/components/chat-message/user-message/user-message.vue.d.ts +3 -1
  14. package/dist/components/index.d.ts +2 -1
  15. package/dist/components/message-tools/message-time/format-message-time.d.ts +8 -0
  16. package/dist/components/message-tools/message-time/message-time.vue.d.ts +8 -0
  17. package/dist/components/message-tools/message-tools.vue.d.ts +11 -1
  18. package/dist/composables/use-custom-tab.d.ts +5 -3
  19. package/dist/composables/use-global-config.d.ts +3 -0
  20. package/dist/composables/use-message-group.d.ts +150 -72
  21. package/dist/icons/execution.d.ts +6 -0
  22. package/dist/icons/tools.d.ts +3 -0
  23. package/dist/index.css +1 -1
  24. package/dist/index.js +3124 -2837
  25. package/dist/index.js.map +1 -1
  26. package/dist/lang/lang.d.ts +8 -7
  27. package/dist/mcp/generated/docs/ai-slash-input.md +2 -0
  28. package/dist/mcp/generated/docs/assistant-message.md +9 -7
  29. package/dist/mcp/generated/docs/chat-container.md +38 -32
  30. package/dist/mcp/generated/docs/chat-input.md +18 -12
  31. package/dist/mcp/generated/docs/cite-content.md +3 -3
  32. package/dist/mcp/generated/docs/desc-panel.md +32 -10
  33. package/dist/mcp/generated/docs/execution-summary.md +3 -3
  34. package/dist/mcp/generated/docs/file-artifact-panel.md +6 -4
  35. package/dist/mcp/generated/docs/file-content.md +89 -73
  36. package/dist/mcp/generated/docs/file-upload-btn.md +16 -18
  37. package/dist/mcp/generated/docs/message-container.md +3 -0
  38. package/dist/mcp/generated/docs/message-render.md +2 -1
  39. package/dist/mcp/generated/docs/message-time.md +180 -0
  40. package/dist/mcp/generated/docs/message-tools.md +47 -12
  41. package/dist/mcp/generated/docs/messages.md +9 -0
  42. package/dist/mcp/generated/docs/toolcall-render.md +82 -43
  43. package/dist/mcp/generated/docs/use-artifact-preview.md +19 -17
  44. package/dist/mcp/generated/docs/use-custom-tab.md +12 -8
  45. package/dist/mcp/generated/docs/use-global-config.md +15 -5
  46. package/dist/mcp/generated/docs/user-message.md +9 -0
  47. package/dist/mcp/generated/docs/user-question-card.md +2 -0
  48. package/dist/mcp/generated/index.json +46 -6
  49. package/dist/types/input.d.ts +6 -0
  50. package/dist/utils/file.d.ts +7 -1
  51. package/dist/utils/index.d.ts +2 -0
  52. package/dist/utils/merge-tools-by-id.d.ts +6 -0
  53. package/dist/utils/upload-file.d.ts +35 -0
  54. package/package.json +1 -1
@@ -1,12 +1,13 @@
1
1
  <!-- AI SUMMARY -->
2
2
  ## 快速了解
3
3
 
4
- 消息悬浮工具栏,组合复制、删除、反馈等工具按钮。 源码位置:src/components/message-tools/message-tools.vue。
4
+ 消息悬浮工具栏,组合复制、删除、反馈等工具按钮;提供 prepend / append 两端插槽承载消息时间等附加内容。 源码位置:src/components/message-tools/message-tools.vue。
5
5
 
6
6
  ### 关联组件
7
7
  - **tool-btn** — 普通工具项由 ToolBtn 渲染
8
8
  - **user-feedback** — like/unlike 时弹出反馈表单
9
9
  - **delete-tool** — id 为 delete 时替换为带确认的删除按钮
10
+ - **message-time** — 通过 prepend / append 插槽嵌入消息时间
10
11
 
11
12
  ---
12
13
  <!-- FULL DOC -->
@@ -20,22 +21,22 @@
20
21
 
21
22
  > **能力域**:工具与反馈
22
23
 
23
- AI 消息的操作工具栏组件,由**左侧消息工具区**和**右侧更新工具区**两部分组成,中间以分隔线分隔。仅 `like` / `unlike` 按钮会弹出反馈表单(`UserFeedback`),其余按钮直接触发 `onAction`。
24
+ AI 消息的操作工具栏组件,由**左侧消息工具区**和**右侧更新工具区**两部分组成,中间以分隔线分隔;两端另有 `prepend` / `append` 插槽用于挂载消息时间等附加内容。仅 `like` / `unlike` 按钮会弹出反馈表单(`UserFeedback`),其余按钮直接触发 `onAction`。
24
25
 
25
26
  ## 组件结构
26
27
 
27
28
  ```
28
- ┌─────────────────────────────────────────────────────┐
29
- │ .ai-message-tools-container
30
- │ ┌─────────────────────┐ │ ┌───────────────────┐
31
- │ │ messageTools │ │ │ updateTools │ │
32
- │ │ copy cite rebuild… │ │ │ like unlike del │ │
33
- │ └─────────────────────┘ │ └───────────────────┘
34
- 左侧区域 分隔线 右侧区域 │
35
- └─────────────────────────────────────────────────────┘
29
+ ┌───────────────────────────────────────────────────────────────────────┐
30
+ │ .ai-message-tools-container(display: flex,gap: 4px)
31
+ ┌────────┐ ┌─────────────────────┐ │ ┌───────────────┐ ┌───────┐
32
+ │#prependmessageTools │ │ │ updateTools │#append│
33
+ │ │ copy cite rebuild… │ │ │ like unlike │ │
34
+ └────────┘ └─────────────────────┘ │ └───────────────┘ └───────┘
35
+ 插槽区 左侧区域 分隔线 右侧区域 插槽区
36
+ └───────────────────────────────────────────────────────────────────────┘
36
37
  ```
37
38
 
38
- - 分隔线(`.ai-divider`)仅在 `updateTools` 非空时显示
39
+ - 分隔线(`.ai-divider`)与**右侧更新工具区**均仅在 `updateTools` 非空时渲染
39
40
  - `updateTools` 中 `id` 为 `like` / `unlike` 的按钮被 `Tippy` 弹窗包裹,点击后展示 `UserFeedback` 反馈表单
40
41
  - `updateTools` 中 `id` 为 `delete` 的按钮使用 `DeleteTool` 组件,点击后展示**确认删除弹窗**(含"删除"/"取消"按钮),确认后触发 `onAction`
41
42
  - `updateTools` 中其他按钮直接触发 `onAction`,不弹表单
@@ -224,6 +225,32 @@ const CONST_UPDATE_TOOLS = [
224
225
 
225
226
  **渲染效果**
226
227
 
228
+ ## 两端插槽(prepend / append)
229
+
230
+ `prepend`(工具图标左侧)与 `append`(工具图标右侧)用于在工具栏两端挂载附加内容,项目内用于放置 [MessageTime 消息时间](/components/feedback/message-time):
231
+
232
+ | 场景 | 使用插槽 | 效果 |
233
+ | --------- | --------- | --------------------------------------- |
234
+ | 用户消息 | `prepend` | 时间显示在工具图标左侧 |
235
+ | AI 消息组 | `append` | 时间显示在工具图标右侧 |
236
+
237
+ ```vue
238
+ <template>
239
+ <MessageTools :on-action="handleAction">
240
+ <template #append>
241
+ <MessageTime :created-at="createdAt" />
242
+ </template>
243
+ </MessageTools>
244
+ </template>
245
+
246
+ <script setup lang="ts">
247
+ import { MessageTime, MessageTools } from '@blueking/chat-x';
248
+ </script>
249
+ ```
250
+
251
+ - 插槽包裹容器(`.ai-message-tools-prepend` / `.ai-message-tools-append`)仅在对应插槽传入时渲染
252
+ - 插槽内容为空时(如消息无 `createdAt`,`MessageTime` 不渲染任何 DOM),包裹容器命中 `:empty` 被收起,不会留下多余间距
253
+
227
254
  ## 工具栏状态控制
228
255
 
229
256
  `messageToolsStatus` 控制工具栏整体状态:
@@ -357,6 +384,13 @@ const CONST_UPDATE_TOOLS = [
357
384
  | -------- | ------------------------------------------------------------- | ------------------------------------------ |
358
385
  | feedback | `(tool: IToolBtn, reasonList: string[], otherReason: string)` | 用户在反馈表单点击"提交"后触发(not 取消) |
359
386
 
387
+ ### Slots
388
+
389
+ | 插槽名 | 作用域参数 | 说明 |
390
+ | ------- | ---------- | ------------------------------------------------ |
391
+ | prepend | — | 工具图标左侧的附加内容,如用户消息的时间 |
392
+ | append | — | 工具图标右侧的附加内容,如 AI 消息组的时间 |
393
+
360
394
  ## 类型定义
361
395
 
362
396
  ```typescript
@@ -382,4 +416,5 @@ enum MessageToolsStatus {
382
416
 
383
417
  - [ToolBtn](/components/feedback/tool-btn) — 单项工具按钮
384
418
  - [UserFeedback](/components/feedback/user-feedback) — 点赞/踩反馈面板
385
- - [DeleteTool](/components/feedback/delete-tool) — 删除二次确认
419
+ - [DeleteTool](/components/feedback/delete-tool) — 删除二次确认
420
+ - [MessageTime](/components/feedback/message-time) — 两端插槽内的消息时间
@@ -54,6 +54,10 @@ interface BaseMessage<T extends MessageType, C = string> {
54
54
  // 消息名称(可选)
55
55
  name?: string;
56
56
 
57
+ // 可选:消息创建时间,ISO 字符串或毫秒时间戳,由消息层(chat-helper)写入
58
+ // 用于 MessageTime 展示;缺省时不展示时间
59
+ createdAt?: number | string;
60
+
57
61
  // 消息属性(可选)
58
62
  property?: {
59
63
  extra?: {
@@ -211,11 +215,16 @@ type ToolCall = {
211
215
  function: FunctionCall;
212
216
  };
213
217
 
218
+ // 调用类型:不填等价于 function
219
+ type FunctionCallType = 'function' | 'mcp' | 'skill';
220
+
214
221
  type FunctionCall = {
215
222
  name: string;
216
223
  arguments: string;
217
224
  description?: string;
218
225
  mcpName?: string;
226
+ // 决定 ToolcallRender 头部前缀(调用工具 / 调用 MCP / 读取 Skill)
227
+ type?: FunctionCallType;
219
228
  };
220
229
 
221
230
  // 示例
@@ -20,29 +20,29 @@
20
20
 
21
21
  > **能力域**:Agent 能力
22
22
 
23
- 展示 AI 调用外部工具/函数过程与结果的渲染组件。由**可折叠头部**和**详情面板**组成,根据 `status` 自动切换颜色和状态文案,支持 MCP 调用识别和内联结果展示。
23
+ 展示 AI 调用外部工具 / MCP / Skill 过程与结果的渲染组件。由**单行可折叠头部**和**详情面板**组成:头部是一段弱化的灰色文本(`#979ba5`),按调用类型给出前缀,进行中用文字渐变闪动表示、结束后在工具名右侧补一段状态与耗时;详情面板默认折叠。
24
24
 
25
25
  ## 组件结构
26
26
 
27
27
  ```
28
- .ai-toolcall-render
29
- ├── .ai-toolcall-render-header(高 40px,class="toolcall-status-{status}"
30
- │ ├── ArrowRightIcon(14×14px,点击切换折叠;默认 rotate(0deg),展开后 rotate(90deg)
31
- │ ├── "调用工具:" / "调用 MCP:"(有 mcpName 时)
32
- │ ├── .toolcall-header-title(工具名,overflow-tips 溢出截断)
33
- │ └── .toolcall-status-title
34
- ├── Loadingpending / streaming)
35
- ├── BkFlowSuccessIcon(success / complete / completed
36
- ├── BkFlowFailedIcon(error
37
- │ ├── 状态文案(调用中 / 调用成功 / 调用失败)
38
- │ └── .toolcall-duration(耗时,如 "(1.2s)")
28
+ .ai-toolcall-render(font-size: 12px,line-height: 20px)
29
+ ├── .ai-toolcall-render-header(单行,整行可点击切换折叠;class="is-expanded" 表示已展开)
30
+ │ ├── ToolCallIcon(.ai-toolcall-icon,16×16px
31
+ │ ├── .toolcall-header-text(内联文本块,溢出截断 + overflow-tips)
32
+ ├── .toolcall-header-title(前缀 + HighlightKeyword(工具名))
33
+ │ │ └── .is-loading(进行中,渐变光带闪动)
34
+ │ └── .toolcall-header-statusv-if 有状态词;括号与耗时为弱显示)
35
+ │ └── .toolcall-header-result(.is-success #2caf5e / .is-error #ea3636
36
+ └── ChevronRightIcon(.ai-chevron-right-icon,10×10px;v-if 非进行中,展开时 rotate(90deg)
39
37
 
40
- └── .ai-toolcall-render-content(v-show,默认折叠)
38
+ └── .ai-toolcall-render-content(v-show,默认折叠,子项 gap: 8px)
41
39
  ├── DescPanel(title="描述",desc=function.description)← 始终渲染
42
40
  ├── DescPanel(title="参数",desc=function.arguments)← 始终渲染
43
41
  └── ToolMessage(v-if="toolCall?.toolMessage")← 有结果时渲染
44
42
  ```
45
43
 
44
+ > **头部悬停/展开反馈**:头部默认 `#979ba5`;`:hover` 或 `.is-expanded` 时,`ToolCallIcon` 与非闪动态的工具名变为 `#313238`,展开态的箭头同样变为 `#313238`。头部不再有背景色与边框(旧版的 `$toolcallStatusMap` 状态底色已随重构移除)。
45
+
46
46
  ## 基础用法
47
47
 
48
48
  ```vue
@@ -78,19 +78,49 @@
78
78
 
79
79
  ## 调用状态
80
80
 
81
- `status` prop 同时控制头部的 CSS class(`toolcall-status-{status}`)、背景/边框颜色、状态文案和状态图标:
81
+ 组件内部把 `status` 归一为**成功 / 失败 / 进行中**三态,不再逐个 status 匹配底色:
82
+
83
+ ```typescript
84
+ isSuccess = [complete, completed, success].includes(status);
85
+ isError = status === 'error' || !!toolCall?.toolMessage?.error; // toolMessage.error 可独立判定失败
86
+ isPending = !isSuccess && !isError; // 其余(含 pending / streaming / stop / undefined)统一视为进行中
87
+ ```
88
+
89
+ | 归一状态 | 命中条件 | 头部渲染 |
90
+ | -------- | ---------------------------------------------------- | -------------------------------------------------------------- |
91
+ | 进行中 | 非成功且非失败(含未传 `status`) | 前缀替换为「正在调用」(Skill 为「正在读取」),标题带 `is-loading` 闪动,无状态段、无箭头 |
92
+ | 成功 | `complete` / `completed` / `success` | 状态段 `( 成功 )`,状态词 `#2caf5e` |
93
+ | 失败 | `status === 'error'` **或** `toolMessage.error` 为真 | 状态段 `( 失败 )`,状态词 `#ea3636` |
94
+
95
+ 关于状态段的三个细节:
82
96
 
83
- | `status` | 状态文案 | 背景色 | 边框色 | 状态图标 |
84
- | ------------------------------------- | -------- | ----------------- | --------- | ------------------- |
85
- | `pending` / `streaming` | 调用中 | `#fafbfd` | `#dcdee5` | `Loading` |
86
- | `complete` / `completed` / `success` | 调用成功 | `#ebfaf0` | `#a1e3ba` | `BkFlowSuccessIcon` |
87
- | `error` | 调用失败 | `#fff0f0` | `#f8b4b4` | `BkFlowFailedIcon` |
88
- | 其他 / `undefined` | 调用中 | —(无匹配 class) | — | — |
97
+ - **只有状态词着色**:`.toolcall-header-result` 只包住「成功 / 失败」,括号与耗时留在 `.toolcall-header-status` 内保持弱显示
98
+ - **括号写法**:头部渲染用半角括号并在两侧补 `&nbsp;` 撑开间距;`overflow-tips` 气泡里的纯文本用全角括号,形如 `调用工具 search(成功,耗时:1.2s)`
99
+ - **失败优先**:`toolMessage.error` 有值时即便 `status` 是成功态也判为失败
89
100
 
90
- > **说明**:`statusTitle` `Completed`(`completed`)与 `Complete` / `Success` 一并视为成功;主题 `$toolcallStatusMap` 同步提供 `completed` 色值。`default` `case Pending` 共享「调用中」文案,`streaming` 与未知 status 命中 `default`。状态图标互斥:`pending` / `streaming` 显示 `Loading`;`success` / `complete` / `completed` 显示 `BkFlowSuccessIcon`;`error` 显示 `BkFlowFailedIcon`。
101
+ 进行中的「文字 loading」由 CSS 实现:`.toolcall-header-title.is-loading` `linear-gradient` + `background-clip: text` 让一条光带以 `1.8s linear infinite` 循环扫过文字;`prefers-reduced-motion: reduce` 下自动关闭动画。
91
102
 
92
103
  **三种状态对比**
93
104
 
105
+ ## 调用类型前缀
106
+
107
+ 非进行中态的前缀由 `function.type` 决定;进行中态工具 / MCP 显示「正在调用」,Skill 显示「正在读取」:
108
+
109
+ | `function.type` | 前缀 | 说明 |
110
+ | ------------------------ | ----------- | ---------------------------------------- |
111
+ | `'function'` / 不传 | 调用工具 | 普通函数调用 |
112
+ | `'mcp'` | 调用 MCP | MCP 调用,通常同时带 `mcpName` |
113
+ | `'skill'` | 读取 Skill | Skill 读取 |
114
+
115
+ ```typescript
116
+ const callType = fn?.type ?? (fn?.mcpName ? 'mcp' : 'function');
117
+ ```
118
+
119
+ - **旧数据兼容**:未下发 `type` 时,有 `mcpName` 仍按 MCP 判定,历史消息展示不变
120
+ - **`type` 优先**:显式 `type: 'function'` 不会被 `mcpName` 覆盖回 MCP,但标题仍是 `{mcpName} / {name}`
121
+
122
+ **三种前缀对比**
123
+
94
124
  ## 工具标题(toolTitle)
95
125
 
96
126
  头部标题的计算规则:
@@ -100,16 +130,20 @@
100
130
  无 mcpName → function.name || toolCall.id
101
131
  ```
102
132
 
103
- `function.name` 为空字符串时,自动回退到 `toolCall.id` 作为标题。标题超出容器宽度时截断并配备 overflow-tips
133
+ `function.name` 为空字符串时,自动回退到 `toolCall.id` 作为标题。前缀、标题与状态段同处一个内联文本块 `.toolcall-header-text`,整体超出容器宽度时统一截断,并由 overflow-tips 展示完整文案。
104
134
 
105
135
  ## 折叠/展开详情面板
106
136
 
107
- 详情面板**默认折叠**,点击头部左侧的 **箭头图标**(14×14px 可点区域,非整行)切换折叠状态。折叠状态由 `collapsed`(默认 `true`)和 `superCollapsed` 两个 `shallowRef` 共同管理,不暴露为 prop/v-model。
137
+ 详情面板**默认折叠**,点击**整行头部**切换折叠状态(旧版仅箭头可点)。折叠状态由 `collapsed`(默认 `true`)和 `superCollapsed` 两个 `shallowRef` 管理,不暴露为 prop/v-model。
108
138
 
109
- | 折叠状态 | 箭头旋转角度 | 详情面板 |
110
- | ------------ | ----------------------- | ------------- |
111
- | 折叠(默认) | `rotate(0deg)`(朝右) | `v-show` 隐藏 |
112
- | 展开 | `rotate(90deg)`(朝下) | 可见 |
139
+ | 折叠状态 | 箭头 | 头部 class | 详情面板 |
140
+ | ------------ | ----------------------------------- | ------------- | ------------- |
141
+ | 折叠(默认) | `ChevronRightIcon` 朝右 | — | `v-show` 隐藏 |
142
+ | 展开 | `rotate(90deg)` 朝下,颜色 `#313238` | `is-expanded` | 可见 |
143
+
144
+ > **进行中不渲染箭头**:`isPending` 为真时箭头隐藏(此时通常还没有结果可看),但头部点击仍会切换详情面板。
145
+ >
146
+ > **关键词联动**:接入 `useKeywordMatch` 后,若上层正在搜索关键词且用户未手动点过头部(`superCollapsed` 为 `null`),面板会按「命中关键词则展开」自动切换;用户一旦点击,`superCollapsed` 接管并固定为手动选择的状态。
113
147
 
114
148
  详情面板由三块区域构成:
115
149
 
@@ -133,6 +167,8 @@ durationDisplay = formatDuration(props.duration || toolCall?.toolMessage?.durati
133
167
  | 未传 `duration`,toolMessage 有 `duration` | 使用 `toolMessage.duration` |
134
168
  | 两者均无 | 不显示耗时 |
135
169
 
170
+ 耗时不再单独占一个元素,而是拼进状态段:有耗时时渲染为 `( 成功,耗时:1.2s )`,无耗时时只保留 `( 成功 )`。进行中态没有状态段,因此也不展示耗时。
171
+
136
172
  ```vue
137
173
  <!-- 方式一:直接传 duration prop(优先) -->
138
174
  <ToolcallRender :tool-call="toolCall" status="complete" :duration="1200" />
@@ -156,32 +192,28 @@ const toolCallWithDuration: ToolCall = {
156
192
  };
157
193
  ```
158
194
 
159
- ## MCP 工具调用
195
+ ## MCP 调用
160
196
 
161
- `function.mcpName` 有值时:
162
-
163
- - 头部文案从 **"调用工具:"** 自动切换为 **"调用 MCP:"**
164
- - 标题格式变为 `{mcpName} / {functionName}`
197
+ `function.type` 为 `'mcp'`(或旧数据仅有 `mcpName`)时,前缀为「调用 MCP」,标题格式变为 `{mcpName} / {functionName}`:
165
198
 
166
199
  ```typescript
167
200
  const mcpToolCall: ToolCall = {
168
201
  id: 'call_mcp_1',
169
202
  type: 'function',
170
203
  function: {
204
+ type: 'mcp', // ← 前缀显示「调用 MCP」;缺省时有 mcpName 也会兼容判定为 MCP
171
205
  name: 'query_table',
172
206
  arguments: JSON.stringify({ table: 'events', limit: 50 }),
173
207
  description: '通过 MCP 协议查询蓝鲸数据平台中的事件数据',
174
- mcpName: 'bk-data-server', // ← 有值时头部显示"调用 MCP:"
208
+ mcpName: 'bk-data-server',
175
209
  },
176
210
  };
177
- // 头部显示:调用 MCPbk-data-server / query_table
211
+ // 头部显示:调用 MCP bk-data-server / query_table(成功,耗时:830ms)
178
212
  ```
179
213
 
180
- **渲染效果**
181
-
182
214
  ## 调用失败
183
215
 
184
- `toolMessage.error` 有值且 `content` 为空时,`ToolMessage` 内部展示错误信息(由 `content || error` 决定)。`status` 设为 `error` 控制头部红色样式:
216
+ `toolMessage.error` 有值且 `content` 为空时,`ToolMessage` 内部展示错误信息(由 `content || error` 决定)。头部状态词是否红色由 `status === 'error'` **或** `toolMessage.error` 任一命中决定,因此下例即使不传 `status` 也会显示失败:
185
217
 
186
218
  ```typescript
187
219
  const failedToolCall: ToolCall = {
@@ -257,15 +289,17 @@ const assistantMessage = {
257
289
  </template>
258
290
  ```
259
291
 
292
+ > **多条工具调用**:`AssistantMessage` 把 `toolCalls` 包在 `.ai-assistant-message-toolcalls` 容器内,条目之间固定 `8px` 间距,不受消息区 `12px` 间距影响。
293
+
260
294
  ## API
261
295
 
262
296
  ### Props
263
297
 
264
- | 属性名 | 类型 | 默认值 | 说明 |
265
- | -------- | --------------- | ------ | --------------------------------------------------------------------------- |
266
- | toolCall | `ToolCall` | — | 工具调用信息对象 |
267
- | status | `MessageStatus` | — | 调用状态,控制头部颜色和状态文案;未传时 `default` 分支显示"调用中" |
268
- | duration | `number` | — | 调用耗时(毫秒),优先于 `toolCall.toolMessage?.duration`;均无时不显示耗时 |
298
+ | 属性名 | 类型 | 默认值 | 说明 |
299
+ | -------- | --------------- | ------ | ----------------------------------------------------------------------------------- |
300
+ | toolCall | `ToolCall` | — | 工具调用信息对象 |
301
+ | status | `MessageStatus` | — | 调用状态,归一为成功 / 失败 / 进行中三态;未传时按进行中渲染(「正在调用」+ 闪动) |
302
+ | duration | `number` | — | 调用耗时(毫秒),优先于 `toolCall.toolMessage?.duration`;均无时状态段不展示耗时 |
269
303
 
270
304
  ## 类型定义
271
305
 
@@ -275,6 +309,7 @@ import {
275
309
  MessageContentType,
276
310
  type ToolCall,
277
311
  type FunctionCall,
312
+ type FunctionCallType,
278
313
  type ToolMessage,
279
314
  } from '@blueking/chat-x';
280
315
 
@@ -286,12 +321,16 @@ type ToolCall = {
286
321
  toolMessage?: Partial<ToolMessage>; // 有值时在详情面板底部内联渲染 ToolMessage
287
322
  };
288
323
 
324
+ // FunctionCallType —— 调用类型
325
+ type FunctionCallType = 'function' | 'mcp' | 'skill';
326
+
289
327
  // FunctionCall —— 函数调用描述
290
328
  type FunctionCall = {
291
329
  name: string; // 函数名;为空时标题 fallback 为 toolCall.id
292
330
  arguments: string; // 调用参数(通常为 JSON 字符串)
293
331
  description?: string; // 工具描述;为空时"描述"区块保留但内容为空白
294
- mcpName?: string; // MCP 服务名;有值时头部改为"调用 MCP:",标题格式变为 "{mcpName} / {name}"
332
+ mcpName?: string; // MCP 服务名;有值时标题格式变为 "{mcpName} / {name}",缺省 type 时兼容判定为 MCP
333
+ type?: FunctionCallType; // 调用类型,决定头部前缀;不传按 mcpName 兼容判定
295
334
  };
296
335
 
297
336
  // ToolMessage —— 工具返回消息
@@ -75,32 +75,30 @@ const { addCustomTab, ensureCustomTab, removeCustomTab } = useCustomTabProvider(
75
75
  // 会话级文件产物聚合已内聚在 useMessageGroup,直接消费
76
76
  const { sessionArtifacts } = useMessageGroup({ keyword, messages, selectedUserMessages });
77
77
 
78
+ const FILE_ARTIFACT_TAB = {
79
+ closable: false,
80
+ label: t('文件产物'),
81
+ name: FILE_ARTIFACT_TAB_NAME,
82
+ order: -1,
83
+ };
84
+
85
+ // 常驻挂载:不随产物有无增删,无产物时由面板展示空态
86
+ ensureCustomTab(FILE_ARTIFACT_TAB);
87
+
78
88
  const { activeArtifactId, setActiveArtifactId } = useArtifactPreviewProvider({
79
89
  getOnArtifactClick: () => props.onArtifactClick,
80
90
  // 点击文件卡片:展开侧栏并选中「文件产物」Tab
81
91
  onOpen: () => {
82
- addCustomTab({
83
- closable: false,
84
- label: t('文件产物'),
85
- name: FILE_ARTIFACT_TAB_NAME,
86
- order: -1,
87
- });
92
+ addCustomTab(FILE_ARTIFACT_TAB);
88
93
  },
89
94
  });
90
95
 
91
- // 有产物时静默挂上 Tab(不抢焦点);无产物时清理
96
+ // 仅维护命中态:无产物清空,命中项失效时回落到第一个
92
97
  watch(sessionArtifacts, list => {
93
98
  if (!list.length) {
94
- removeCustomTab(FILE_ARTIFACT_TAB_NAME);
95
99
  setActiveArtifactId('');
96
100
  return;
97
101
  }
98
- ensureCustomTab({
99
- closable: false,
100
- label: t('文件产物'),
101
- name: FILE_ARTIFACT_TAB_NAME,
102
- order: -1,
103
- });
104
102
  if (!list.some(item => item.outputId === activeArtifactId.value)) {
105
103
  setActiveArtifactId(list[0].outputId);
106
104
  }
@@ -211,8 +209,12 @@ ArtifactFileCard(点击)
211
209
  └─ FileArtifactPanel(列表 + 下载头,@select → setActiveArtifactId)
212
210
  └─ ArtifactPreviewHost(loader + 分类型 renderer)
213
211
 
214
- sessionArtifacts 变化(有产物)
215
- └─ ensureCustomTab(FILE_ARTIFACT_TAB_NAME) 静默挂上,不抢当前选中(如执行情况)
212
+ 容器初始化
213
+ └─ ensureCustomTab(FILE_ARTIFACT_TAB_NAME) 常驻挂上(不展开侧栏);因 order:-1 排在首位,
214
+ 未主动切换过 Tab 时会成为默认选中面板;无产物时由面板展示整块空态
215
+
216
+ sessionArtifacts 变化
217
+ └─ 仅维护命中态(无产物清空,命中项失效回落第一个);不增删 Tab
216
218
  ```
217
219
 
218
220
  分类型预览策略见 [FileArtifactPanel 预览机制](../components/message/file-artifact-panel#预览机制)。
@@ -222,7 +224,7 @@ sessionArtifacts 变化(有产物)
222
224
  - **职责单一**:composable 不直接调用 `useCustomTab`,侧栏 Tab 打开逻辑由 `onOpen` 注入;也不做正文 fetch / iframe 渲染
223
225
  - **ShallowRef 优先**:`activeArtifactId` 使用 `shallowRef`,避免不必要的深层响应式开销
224
226
  - **Consumer 兜底**:`useArtifactPreviewConsumer` 无 Provider 时返回 `undefined`,文件卡片在无容器上下文时自动不可点击
225
- - **与 useCustomTab 协作**:点击卡片走 `addCustomTab`(展开 + 选中);会话已有产物时走 `ensureCustomTab`(只挂载,不抢焦点);无文件产物时由容器 `removeCustomTab` 清理
227
+ - **与 useCustomTab 协作**:点击卡片走 `addCustomTab`(展开 + 选中);容器初始化时走 `ensureCustomTab` 常驻挂载(不展开;因 `order: -1` 在未主动切换前会成为默认选中),无产物也不移除,由面板展示空态
226
228
 
227
229
  ## 关联组件
228
230
 
@@ -1,7 +1,7 @@
1
1
  <!-- AI SUMMARY -->
2
2
  ## 快速了解
3
3
 
4
- useCustomTabProvider 返回 tabs、selectedTab、isCollapse 及 add/ensure/remove/selectCustomTab,并通过 provide 共享;可选 onTabChange 在切换时拉取数据。 ensureCustomTab 只挂载/合并元信息,不展开侧栏、不切换选中;addCustomTab 会展开并选中。 useCustomTabConsumer 在后代注入同一套 API,常用于侧栏动态节点详情等。EXECUTION_TAB_NAME 标识默认「执行情况」Tab。 ChatContainer 侧栏集成 Provider 与 Tab UI。
4
+ useCustomTabProvider 返回 tabs、selectedTab、isCollapse 及 add/ensure/remove/selectCustomTab,并通过 provide 共享;可选 onTabChange 在切换时拉取数据、可选 collapsed 注入受控折叠态 ref。 ensureCustomTab 只挂载/合并元信息,不展开侧栏、不主动切换选中;addCustomTab 会展开并选中。 未被主动切换过时,选中态默认跟随 Tab 栏首位(order 最小),如常驻的「文件产物」。 useCustomTabConsumer 在后代注入同一套 API,常用于侧栏动态节点详情等。EXECUTION_TAB_NAME 标识默认「执行情况」Tab。 ChatContainer 侧栏集成 Provider 与 Tab UI。
5
5
 
6
6
  ### 关联组件
7
7
  - **chat-container** — Provider 与侧栏 Tab 主场景
@@ -21,6 +21,8 @@ Provider/Consumer 模式的自定义 Tab 管理,用于 `ChatContainer` 侧边
21
21
 
22
22
  ```typescript
23
23
  function useCustomTabProvider<T extends Record<string, unknown>>(options: {
24
+ // 侧栏折叠态;由容器传入受控 ref(如 ChatContainer 的 v-model:asideCollapsed),缺省内部自持
25
+ collapsed?: Ref<boolean>;
24
26
  // 执行情况 Tab 是否展示,缺省 true;传 getter 以保持响应式
25
27
  executionTabVisible?: () => boolean | undefined;
26
28
  onTabChange?: (tab: CustomTab<T>) => void;
@@ -28,7 +30,7 @@ function useCustomTabProvider<T extends Record<string, unknown>>(options: {
28
30
  tabs: ShallowRef<CustomTab<T>[]>;
29
31
  displayTabs: ComputedRef<CustomTab<T>[]>;
30
32
  selectedTab: Ref<CustomTab<T>>;
31
- isCollapse: ShallowRef<boolean>;
33
+ isCollapse: Ref<boolean>;
32
34
  addCustomTab: (tab: CustomTab<T>) => void;
33
35
  ensureCustomTab: (tab: CustomTab<T>) => void;
34
36
  removeCustomTab: (tabName: string) => void;
@@ -88,7 +90,7 @@ tabManager?.addCustomTab({
88
90
  },
89
91
  });
90
92
 
91
- // 仅确保 Tab 存在(不展开、不切换选中)—— 如侧栏已因执行情况打开时同步挂上文件产物
93
+ // 仅确保 Tab 存在(不展开、不切换选中)—— 如常驻挂上文件产物 Tab
92
94
  tabManager?.ensureCustomTab({
93
95
  name: 'file-artifact',
94
96
  label: '文件产物',
@@ -114,10 +116,10 @@ tabManager?.removeCustomTab('node-detail-123');
114
116
  | --------------- | --------------------------- | ------------------------------------------------- |
115
117
  | tabs | `ShallowRef<CustomTab[]>` | 所有 Tab 列表(含默认的执行情况 Tab,保留隐藏项) |
116
118
  | displayTabs | `ComputedRef<CustomTab[]>` | Tab 栏实际展示列表:过滤 `visible === false`,按 `order` 升序稳定排序 |
117
- | selectedTab | `Ref<CustomTab>` | 当前选中的 Tab;选中项被隐藏时自动回退到首个可见 Tab |
118
- | isCollapse | `ShallowRef<boolean>` | 侧边栏折叠状态;`addCustomTab` 时自动设为 `false` |
119
+ | selectedTab | `Ref<CustomTab>` | 当前选中的 Tab;未被主动切换过时跟随 Tab 栏首位,选中项被隐藏时自动回退到首个可见 Tab |
120
+ | isCollapse | `Ref<boolean>` | 侧边栏折叠状态;传入 `collapsed` 时即该受控 ref(读写都作用于外部),否则为内部状态;`addCustomTab` 时自动设为 `false` |
119
121
  | addCustomTab | `(tab: CustomTab) => void` | 添加/合并 Tab,**展开侧栏并选中**目标 Tab |
120
- | ensureCustomTab | `(tab: CustomTab) => void` | 添加/合并 Tab,**不展开、不切换选中**;用于静默挂载(如文件产物) |
122
+ | ensureCustomTab | `(tab: CustomTab) => void` | 添加/合并 Tab,**不展开、不主动切换选中**;用于常驻挂载(如文件产物) |
121
123
  | removeCustomTab | `(tabName: string) => void` | 移除指定 Tab |
122
124
  | selectCustomTab | `(tab: CustomTab) => void` | 切换到指定 Tab,触发 `onTabChange` 回调 |
123
125
  | resetCustomTab | `() => void` | 重置为仅保留「执行情况」Tab、折叠侧栏并选中默认 Tab;`ChatContainer` 在卸载时调用,避免残留自定义 Tab |
@@ -147,9 +149,11 @@ interface CustomTab<T = Record<string, unknown>> {
147
149
  - 排序为稳定排序,`order` 相同的 Tab 保持插入先后顺序
148
150
  - 选中的 Tab 被配置隐藏时,内容不再渲染,自动切换到首个可见 Tab
149
151
  - `addCustomTab` 同时展开侧边栏(`isCollapse = false`)并在 `nextTick` 后自动选中目标 Tab;同名 Tab 合并更新
150
- - `ensureCustomTab` 与 `addCustomTab` 共用合并逻辑,但不改 `isCollapse`、不切换 `selectedTab`;适合「侧栏已打开时同步挂上文件产物」等场景
152
+ - `ensureCustomTab` 与 `addCustomTab` 共用合并逻辑,但不改 `isCollapse`、自身不切换 `selectedTab`;适合「常驻挂载文件产物 Tab」等场景
153
+ - 默认选中跟随 Tab 栏首位:只要没调用过 `selectCustomTab` / `addCustomTab`,挂上更靠前(`order` 更小)的 Tab 就会成为选中项,因此常驻的「文件产物」(`order: -1`)是侧栏默认面板;一旦主动切换过便不再跟随。`resetCustomTab` 会重置该标记
154
+ - 折叠态支持受控:传入 `collapsed` 后 Provider 不再自持状态,内部展开动作直接写回该 ref,容器即可通过 `v-model` 把状态交给外部判断
151
155
 
152
156
  ## 关联组件
153
157
 
154
158
  - [ChatContainer](../components/setup/chat-container) — 侧栏 Tab 与自定义面板
155
- - [useArtifactPreview](./use-artifact-preview) — 文件产物 Tab:有产物时 `ensureCustomTab`,点击卡片时 `addCustomTab`
159
+ - [useArtifactPreview](./use-artifact-preview) — 文件产物 Tab:初始化 `ensureCustomTab` 常驻挂载,点击卡片时 `addCustomTab`
@@ -1,10 +1,11 @@
1
1
  <!-- AI SUMMARY -->
2
2
  ## 快速了解
3
3
 
4
- useGlobalConfig 接收 GlobalConfig(含 size?: ComputedRef<AiSizeMode>、supportUpload: ComputedRef<boolean>),以 GLOBAL_CONFIG_TOKEN provide 给后代; injectGlobalConfig 在子组件中取出配置,无 Provider 时返回 undefined。ChatContainer 在 setup 中调用 useGlobalConfig 注入 size 与 supportUpload; 后代组件可通过 injectGlobalConfig 读取配置;字号主题主要通过根节点 data-ai-size 与 CSS 变量生效。
4
+ useGlobalConfig 接收 GlobalConfig(含 size?: ComputedRef<AiSizeMode>、supportUpload: ComputedRef<boolean>、timezone?: ComputedRef<string | undefined>),以 GLOBAL_CONFIG_TOKEN provide 给后代; injectGlobalConfig 在子组件中取出配置,无 Provider 时返回 undefined。ChatContainer 在 setup 中调用 useGlobalConfig 注入 size、supportUploadtimezone; 后代组件可通过 injectGlobalConfig 读取配置;字号主题主要通过根节点 data-ai-size 与 CSS 变量生效。
5
5
 
6
6
  ### 关联组件
7
7
  - **chat-container** — 根容器调用 useGlobalConfig 注入 supportUpload
8
+ - **message-time** — 消息时间组件读取 timezone
8
9
 
9
10
  ---
10
11
  <!-- FULL DOC -->
@@ -13,7 +14,7 @@ useGlobalConfig 接收 GlobalConfig(含 size?: ComputedRef<AiSizeMode>、suppo
13
14
 
14
15
  > **分类**:composable
15
16
 
16
- 在聊天容器根组件与子组件之间通过 Vue `provide` / `inject` 共享**全局展示相关配置**(当前包括字号主题档位 `size`、是否支持上传 `supportUpload`)。与 Teleport 插槽 ID 无关。
17
+ 在聊天容器根组件与子组件之间通过 Vue `provide` / `inject` 共享**全局展示相关配置**(当前包括字号主题档位 `size`、是否支持上传 `supportUpload`、消息时间时区 `timezone`)。与 Teleport 插槽 ID 无关。
17
18
 
18
19
  > 字号主题主要通过 `ChatContainer` 根节点的 `data-ai-size` 与 CSS 变量(`--ai-font-size` 等)生效;`GlobalConfig.size` 供后代在逻辑层读取当前档位,样式层无需逐组件传参。
19
20
 
@@ -25,10 +26,11 @@ ChatContainer(根)
25
26
  ├── useGlobalConfig({
26
27
  │ size: computed(() => props.size ?? 'small'),
27
28
  │ supportUpload: computed(() => props.supportUpload ?? false),
29
+ │ timezone: computed(() => props.timezone),
28
30
  │ })
29
- │ └── provide(GLOBAL_CONFIG_TOKEN, { size, supportUpload })
31
+ │ └── provide(GLOBAL_CONFIG_TOKEN, { size, supportUpload, timezone })
30
32
 
31
- └── MessageContainer → … → UserMessage 等
33
+ └── MessageContainer → … → UserMessage / MessageTime
32
34
 
33
35
  UserMessage(后代)
34
36
  ├── injectGlobalConfig()
@@ -51,11 +53,14 @@ UserMessage(后代)
51
53
  const props = defineProps<{
52
54
  size?: 'normal' | 'small';
53
55
  supportUpload?: boolean;
56
+ timezone?: string;
54
57
  }>();
55
58
 
56
59
  useGlobalConfig({
57
60
  size: computed(() => props.size ?? 'small'),
58
61
  supportUpload: computed(() => props.supportUpload ?? false),
62
+ // 无默认值:未配置时由 MessageTime 回退到浏览器时区
63
+ timezone: computed(() => props.timezone),
59
64
  });
60
65
  </script>
61
66
  ```
@@ -88,11 +93,13 @@ export type AiSizeMode = 'normal' | 'small';
88
93
  export type GlobalConfig = {
89
94
  size?: ComputedRef<AiSizeMode>;
90
95
  supportUpload: ComputedRef<boolean>;
96
+ timezone?: ComputedRef<string | undefined>;
91
97
  };
92
98
 
93
99
  export function useGlobalConfig(options: GlobalConfig): {
94
100
  size?: ComputedRef<AiSizeMode>;
95
101
  supportUpload: ComputedRef<boolean>;
102
+ timezone?: ComputedRef<string | undefined>;
96
103
  };
97
104
 
98
105
  export function injectGlobalConfig(): GlobalConfig | undefined;
@@ -110,6 +117,7 @@ export function injectGlobalConfig(): GlobalConfig | undefined;
110
117
  | --------------- | ------------------------------------------------------------------------ |
111
118
  | `size` | 可选。字号主题档位 `normal`(14px)/ `small`(12px),与 `ChatContainer.size` 对齐 |
112
119
  | `supportUpload` | 是否支持上传,与根容器 `ChatContainer` 的 `supportUpload` 等展示策略对齐 |
120
+ | `timezone` | 可选。消息时间展示所用的 IANA 时区名,与 `ChatContainer.timezone` 对齐;未配置时 `MessageTime` 按浏览器时区展示 |
113
121
 
114
122
  ### `useGlobalConfig(options)`
115
123
 
@@ -117,6 +125,7 @@ export function injectGlobalConfig(): GlobalConfig | undefined;
117
125
  | ----------------------- | ------------------------------------------------------------------------------------- |
118
126
  | `options.size` | 可选。字号主题档位,建议使用 `computed(() => props.size ?? 'small')` 与根 props 同步 |
119
127
  | `options.supportUpload` | 是否支持上传,建议使用 `computed(() => props.supportUpload ?? false)` 与根 props 同步 |
128
+ | `options.timezone` | 可选。消息时间时区,建议使用 `computed(() => props.timezone)` 与根 props 同步;不设默认值,交由 `MessageTime` 回退浏览器时区 |
120
129
 
121
130
  - 调用后立即 `provide(GLOBAL_CONFIG_TOKEN, options)`。
122
131
  - 必须在具有组件实例上下文的 `setup` 中调用(与 Vue `provide` 要求一致)。
@@ -136,5 +145,6 @@ export function injectGlobalConfig(): GlobalConfig | undefined;
136
145
 
137
146
  ## 关联组件
138
147
 
139
- - [ChatContainer](../components/setup/chat-container) — 调用 `useGlobalConfig` 注入 `size` 与 `supportUpload`
148
+ - [ChatContainer](../components/setup/chat-container) — 调用 `useGlobalConfig` 注入 `size`、`supportUpload` 与 `timezone`
149
+ - [MessageTime](../components/feedback/message-time) — 读取 `timezone` 展示消息时间
140
150
  - [主题配置](../theme/theme) — `data-ai-size` 与 CSS 变量说明
@@ -6,6 +6,7 @@
6
6
  ### 关联组件
7
7
  - **message-render** — 由 MessageRender 在 role 为 user 时创建
8
8
  - **message-tools** — 消息工具栏交互与状态由 MessageTools 体系承载
9
+ - **message-time** — createdAt 经工具栏 prepend 插槽展示
9
10
  - **message-container** — 嵌入列表时由 MessageContainer 管理分组与多选
10
11
  - **chat-input** — 编辑态普通消息使用 ChatInput
11
12
 
@@ -47,8 +48,11 @@
47
48
  v-if: messageToolsStatus !== 'hidden'
48
49
  visibility: hidden(默认)→ visible(:hover 时)
49
50
  tools: [copy, cite, edit, delete],updateTools: []
51
+ #prepend slot → MessageTime(createdAt,工具图标左侧)
50
52
  ```
51
53
 
54
+ > **时间随工具栏显隐**:时间位于工具栏内,与工具按钮共用 `visibility` 控制,因此同样在悬停消息时才可见。
55
+
52
56
  **编辑模式**(点击 `edit` 按钮后 `isEdit=true`)
53
57
 
54
58
  ```
@@ -311,6 +315,8 @@ binaryFiles 有值 → 进入编辑模式(editContent 可为空)
311
315
  | `edit` | 编辑 | 切换 `isEdit=true`,进入编辑模式 |
312
316
  | `delete` | 删除 | 无内置行为,需通过 `onAction` 外部处理 |
313
317
 
318
+ 可通过 `messageTools` 按 id 覆盖/追加,`{ id: 'edit', hidden: true }` 可隐藏内置项。
319
+
314
320
  ```vue
315
321
  <!-- 经 MessageRender 控制工具栏状态 -->
316
322
  <MessageRender
@@ -356,7 +362,9 @@ binaryFiles 有值 → 进入编辑模式(editContent 可为空)
356
362
  | 属性名 | 类型 | 说明 |
357
363
  | ------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
358
364
  | content | `string \| InputContent[]` | 消息内容,字符串或含 text/binary 的数组 |
365
+ | createdAt | `number \| string` | 消息创建时间,经 `MessageTools` 的 `#prepend` 插槽交给 `MessageTime` 渲染在工具图标左侧;无值时不展示 |
359
366
  | property | `{ extra?: MessageExtra; artifacts?: AIFileInfo[] }` | 附加属性;本组件消费 `extra.cite` / `shortcut` / `context` |
367
+ | messageTools | `IToolBtn[]` | 自定义用户消息工具组;按 id 与 `CONST_USER_MESSAGE_TOOLS` 合并,`{ id, hidden: true }` 可隐藏 |
360
368
  | messageToolsStatus | `MessageToolsStatus` | 工具按钮状态,`disabled` 禁用、`hidden` 从 DOM 移除 |
361
369
  | onAction | `MessageToolsProps['onAction']` | 工具回调;`copy`/`edit` 有内置行为,`cite`/`delete` 需外部处理 |
362
370
  | onInputConfirm | `(content: UserMessage['content'], docSchema: TagSchema) => Promise<void>` | 普通消息编辑确认回调 |
@@ -417,4 +425,5 @@ type MessageExtra = {
417
425
 
418
426
  - [MessageRender](/components/message/message-render) — user 角色由其实例化
419
427
  - [MessageTools](/components/feedback/message-tools) — 工具栏交互
428
+ - [MessageTime](/components/feedback/message-time) — 工具栏左侧的消息时间
420
429
  - [MessageContainer](/components/setup/message-container) — 列表与多选容器
@@ -188,6 +188,8 @@ const payload = buildSkipResumePayload(interrupt);
188
188
 
189
189
  `ChatContainer` 提供同名 `#interruptQuestion` slot,参数与 `#question` 一致,透传自输入区上方的 `UserQuestionCard`。
190
190
 
191
+ > **跳过按钮禁用态**:`disabled` 时文字与图标同步变灰(`currentColor` / `#c4c6cc`)。
192
+
191
193
  ## API
192
194
 
193
195
  ### UserQuestionCard Props