@blueking/chat-x 0.0.47-beta.4 → 0.0.49-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 (56) hide show
  1. package/dist/ag-ui/types/file.d.ts +23 -0
  2. package/dist/ag-ui/types/index.d.ts +1 -0
  3. package/dist/ag-ui/types/messages.d.ts +2 -0
  4. package/dist/components/chat-input/chat-input.vue.d.ts +15 -2
  5. package/dist/components/chat-input/input-attachment/input-attachment.vue.d.ts +4 -2
  6. package/dist/components/chat-input/model-selector/capabilities.d.ts +3 -0
  7. package/dist/components/chat-input/model-selector/index.d.ts +3 -0
  8. package/dist/components/chat-input/model-selector/model-selector-panel.vue.d.ts +26 -0
  9. package/dist/components/chat-input/model-selector/model-selector-trigger.vue.d.ts +14 -0
  10. package/dist/components/chat-input/model-selector/model-selector.vue.d.ts +39 -0
  11. package/dist/components/chat-input/model-selector/types.d.ts +61 -0
  12. package/dist/components/chat-input/model-selector/use-model-selector.d.ts +17 -0
  13. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-file-card.vue.d.ts +14 -0
  14. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/artifact-preview-host.vue.d.ts +8 -0
  15. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/preview-strategy.d.ts +9 -0
  16. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/html-preview.vue.d.ts +6 -0
  17. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/markdown-preview.vue.d.ts +6 -0
  18. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/txt-preview.vue.d.ts +6 -0
  19. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/url-iframe-preview.vue.d.ts +6 -0
  20. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/use-artifact-preview-loader.d.ts +21 -0
  21. package/dist/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue.d.ts +12 -0
  22. package/dist/components/chat-message/assistant-message/message-artifacts/file-icon.d.ts +29 -0
  23. package/dist/components/chat-message/assistant-message/message-artifacts/message-artifacts.vue.d.ts +10 -0
  24. package/dist/components/chat-message/message-container/message-container.vue.d.ts +2 -0
  25. package/dist/components/index.d.ts +3 -1
  26. package/dist/composables/index.d.ts +1 -0
  27. package/dist/composables/use-artifact-preview.d.ts +59 -0
  28. package/dist/composables/use-message-group.d.ts +434 -0
  29. package/dist/icons/file.d.ts +24 -0
  30. package/dist/icons/index.d.ts +1 -0
  31. package/dist/icons/input.d.ts +7 -0
  32. package/dist/index.css +1 -1
  33. package/dist/index.js +2761 -1984
  34. package/dist/index.js.map +1 -1
  35. package/dist/lang/lang.d.ts +10 -1
  36. package/dist/mcp/generated/docs/activity-message.md +122 -97
  37. package/dist/mcp/generated/docs/assistant-message.md +125 -62
  38. package/dist/mcp/generated/docs/chat-container.md +269 -76
  39. package/dist/mcp/generated/docs/chat-input.md +57 -0
  40. package/dist/mcp/generated/docs/file-artifact-panel.md +279 -0
  41. package/dist/mcp/generated/docs/info-message.md +23 -7
  42. package/dist/mcp/generated/docs/input-attachment.md +1 -0
  43. package/dist/mcp/generated/docs/loading-message.md +36 -17
  44. package/dist/mcp/generated/docs/message-container.md +47 -0
  45. package/dist/mcp/generated/docs/message-render.md +44 -33
  46. package/dist/mcp/generated/docs/message-tools.md +5 -1
  47. package/dist/mcp/generated/docs/model-selector.md +157 -0
  48. package/dist/mcp/generated/docs/reasoning-message.md +15 -11
  49. package/dist/mcp/generated/docs/tool-btn.md +33 -4
  50. package/dist/mcp/generated/docs/tool-message.md +61 -45
  51. package/dist/mcp/generated/docs/use-artifact-preview.md +237 -0
  52. package/dist/mcp/generated/docs/use-message-group.md +24 -0
  53. package/dist/mcp/generated/docs/user-message.md +185 -121
  54. package/dist/mcp/generated/index.json +109 -11
  55. package/dist/types/tool.d.ts +6 -2
  56. package/package.json +2 -2
@@ -0,0 +1,279 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ 汇总当前会话所有 AssistantMessage 的 artifacts,支持关键词搜索、列表选中与下载; 预览区委托 ArtifactPreviewHost:按类型走 text_from_download(html / markdown / md / txt / json) 或 preview_url_iframe(其余类型);download_url / preview_url 经 onArtifactClick 异步获取。 源码位置:src/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue。
5
+
6
+ ### 关联组件
7
+ - **assistant-message** — 文件产物来源于 AssistantMessage.property.artifacts
8
+ - **chat-container** — 面板挂载在侧栏「文件产物」Tab(固定、不可关闭),并通过 onArtifactClick 异步取链
9
+ - **execution-summary** — 同为 ChatContainer 侧栏 Tab 面板,交互形态一致
10
+ - **message-loading** — ArtifactPreviewHost 取链 / 拉取正文过程使用 MessageLoading
11
+
12
+ ---
13
+ <!-- FULL DOC -->
14
+
15
+ # FileArtifactPanel 文件产物预览
16
+
17
+ ## 源码事实
18
+
19
+ - **源码位置**:`src/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue`
20
+ - **能力域**:消息系统
21
+ - **能力说明**:汇总当前会话全部文件产物;左侧列表搜索与选中,右侧预览委托内部 `ArtifactPreviewHost`。
22
+
23
+ > **导出说明**:内部侧栏面板组件,**通常不直接使用**;由 `ChatContainer` 在「文件产物」Tab 内自动挂载。预览加载与渲染为同目录下 `artifact-preview/` 内部实现,不单独导出。
24
+
25
+ 点击 AI 回复中的[文件卡片](/components/message/assistant-message)后,`ChatContainer` 侧栏会弹出固定的「文件产物」Tab,聚合展示当前会话**所有** `AssistantMessage` 的文件产物,并命中被点击的文件进行预览。
26
+
27
+ 面板左侧为可搜索的文件列表,右侧为预览区。通常不需要直接使用,由 `ChatContainer` 在侧栏内自动渲染。
28
+
29
+ ## 核心能力
30
+
31
+ - **会话级聚合**:拍平当前会话所有 `AssistantMessage.property.artifacts`,统一在一个列表内展示
32
+ - **唯一命中**:同一会话可能出现多个消息 + 同名文件,文件名不可作唯一键,统一用 `messageUid#消息内下标#outputId` 生成全局唯一 id
33
+ - **关键词搜索**:按文件名实时过滤列表
34
+ - **异步取链**:`AIFileInfo` 本身不含 `url` / `previewUrl`,通过 `ChatContainer` 的 `onArtifactClick` 按 `outputId` 缓存获取 `download_url` / `preview_url`
35
+ - **职责拆分**:
36
+ - **面板本身**:列表、搜索、预览头(文件名 / 图标 / 下载)
37
+ - **`ArtifactPreviewHost`**:按策略加载正文或预览 URL,分派到对应 renderer;展示 loading / empty / error(含重试)
38
+ - **未传 `onArtifactClick`**:下载按钮隐藏,预览区展示无数据
39
+
40
+ ## 基础用法
41
+
42
+ 面板**未从包入口导出**,业务侧请走下方「业务接入」;下列示例仅用于文档站 / 本地调试(与 `ExecutionSummary` 文档站写法一致:相对路径引入 + 自行挂 Provider)。
43
+
44
+ ```vue
45
+ <template>
46
+ <div style="height: 480px; border: 1px solid #dcdee5; border-radius: 8px; overflow: hidden;">
47
+ <FileArtifactPanel
48
+ :active-id="activeArtifactId"
49
+ :artifacts="sessionArtifacts"
50
+ @select="handleSelect"
51
+ />
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { shallowRef } from 'vue'
57
+ import { buildArtifactId, useArtifactPreviewProvider } from '@blueking/chat-x'
58
+ import type { AIFileInfo, SessionArtifact } from '@blueking/chat-x'
59
+ // 内部组件:仅文档 / 调试;业务请用 ChatContainer 自动挂载
60
+ import FileArtifactPanel from './message-artifacts/file-artifact-panel.vue'
61
+
62
+ const files: AIFileInfo[] = [
63
+ { name: '周报.html', outputId: 'a-html', size: 10240, type: 'html' },
64
+ { name: '说明.md', outputId: 'a-md', size: 8192, type: 'md' },
65
+ { name: '纪要.txt', outputId: 'a-txt', size: 4096, type: 'txt' },
66
+ { name: '配置.json', outputId: 'a-json', size: 2048, type: 'json' },
67
+ { name: '立项.pdf', outputId: 'a-pdf', size: 204800, type: 'pdf' },
68
+ ]
69
+
70
+ const sessionArtifacts: SessionArtifact[] = files.map((file, index) => ({
71
+ ...file,
72
+ artifactId: buildArtifactId('msg-1', index, file.outputId),
73
+ messageUid: 'msg-1',
74
+ }))
75
+
76
+ useArtifactPreviewProvider({
77
+ getOnArtifactClick: () => async file => {
78
+ // 文本类返回可 fetch 的 download_url;iframe 类返回 preview_url
79
+ const res = await api.getArtifactUrls(file.outputId)
80
+ return { download_url: res.download_url, preview_url: res.preview_url }
81
+ },
82
+ onOpen: () => {},
83
+ })
84
+
85
+ const activeArtifactId = shallowRef(sessionArtifacts[0].artifactId)
86
+ const handleSelect = (id: string) => {
87
+ activeArtifactId.value = id
88
+ }
89
+ </script>
90
+ ```
91
+
92
+ **渲染效果**(点击左侧列表切换类型;文本类直渲染,PDF 走 iframe。Mock 取链约 600ms)
93
+
94
+ ## 业务接入(ChatContainer)
95
+
96
+ 日常用法是给容器传 `messages`(含 `property.artifacts`)与 `onArtifactClick`,点击文件卡片即可打开侧栏面板:
97
+
98
+ ```vue
99
+ <template>
100
+ <ChatContainer
101
+ v-model="input"
102
+ :messages="messages"
103
+ :on-artifact-click="onArtifactClick"
104
+ @send-message="handleSend"
105
+ />
106
+ </template>
107
+
108
+ <script setup lang="ts">
109
+ import { ref, shallowRef } from 'vue'
110
+ import {
111
+ ChatContainer,
112
+ MessageRole,
113
+ MessageStatus,
114
+ type AIFileInfo,
115
+ type Message,
116
+ } from '@blueking/chat-x'
117
+
118
+ const input = ref('')
119
+ const messages = shallowRef<Message[]>([
120
+ {
121
+ id: 'u1',
122
+ messageId: 'u1',
123
+ role: MessageRole.User,
124
+ status: MessageStatus.Complete,
125
+ content: '整理本周评审材料',
126
+ },
127
+ {
128
+ id: 'a1',
129
+ messageId: 'a1',
130
+ uid: 'assistant-uid-1',
131
+ role: MessageRole.Assistant,
132
+ status: MessageStatus.Complete,
133
+ content: '已生成评审材料,点击卡片可在侧栏预览:',
134
+ property: {
135
+ artifacts: [
136
+ { name: '周报.html', outputId: 'a-html', size: 10240, type: 'html' },
137
+ { name: '说明.md', outputId: 'a-md', size: 8192, type: 'md' },
138
+ { name: '配置.json', outputId: 'a-json', size: 2048, type: 'json' },
139
+ { name: '立项.pdf', outputId: 'a-pdf', size: 204800, type: 'pdf' },
140
+ ] satisfies AIFileInfo[],
141
+ },
142
+ },
143
+ ])
144
+
145
+ const onArtifactClick = async (file: AIFileInfo) => {
146
+ const res = await api.getArtifactUrls(file.outputId)
147
+ return {
148
+ download_url: res.download_url,
149
+ preview_url: res.preview_url,
150
+ }
151
+ }
152
+
153
+ const handleSend = () => {
154
+ /* ... */
155
+ }
156
+ </script>
157
+ ```
158
+
159
+ ## 触发链路
160
+
161
+ ```
162
+ ArtifactFileCard(点击文件卡片)
163
+ └─ useArtifactPreviewConsumer().openPreview({ file, index, messageUid })
164
+ └─ useArtifactPreviewProvider(ChatContainer 内)
165
+ ├─ 记录命中文件 activeArtifactId
166
+ └─ onOpen → addCustomTab('file-artifact') 展开并选中侧栏 Tab
167
+ └─ FileArtifactPanel
168
+ ├─ 列表 @select → setActiveArtifactId
169
+ ├─ 下载 → resolveArtifactUrls + triggerArtifactDownload
170
+ └─ ArtifactPreviewHost
171
+ ├─ useArtifactPreviewLoader(策略 + fetch / 取链,防竞态)
172
+ └─ HtmlPreview | MarkdownPreview | TxtPreview | UrlIframePreview
173
+ ```
174
+
175
+ - 文件卡片通过 `useArtifactPreviewConsumer` 注入预览上下文,无 Provider 时卡片不可点击(兜底 `undefined`)
176
+ - `ChatContainer` 通过 `useArtifactPreviewProvider` 提供上下文,并把「打开侧栏 Tab」这一副作用以 `onOpen` 注入,保持 composable 职责单一
177
+ - 侧栏「文件产物」Tab 固定不可关闭,`order: -1` 排在「执行情况」之前;会话切换或无文件产物时自动移除
178
+
179
+ ## 唯一 id 规则
180
+
181
+ 同一会话可能存在多个 `AssistantMessage`,且不同消息里可能有同名文件,因此**文件名不可作为唯一键**。统一由 `buildArtifactId` 生成:
182
+
183
+ ```typescript
184
+ import { buildArtifactId } from '@blueking/chat-x';
185
+
186
+ // messageUid#消息内下标#outputId
187
+ buildArtifactId('msg-a', 2, 'output-9'); // => 'msg-a#2#output-9'
188
+ ```
189
+
190
+ Provider 侧聚合与文件卡片侧透传必须使用同一规则,保证命中一致。
191
+
192
+ ## 预览机制
193
+
194
+ 预览由内部 `getArtifactPreviewStrategy(type)` 决定 **加载方式** 与 **渲染器**;面板不直接写死类型分支。
195
+
196
+ | 文件类型 | load | 取链字段 | renderer |
197
+ | -------- | ---- | -------- | -------- |
198
+ | `html` | `text_from_download` | `download_url` → `fetch` 正文 | `HtmlPreview`(`<iframe srcdoc>`) |
199
+ | `markdown` / `md` | `text_from_download` | 同上 | `MarkdownPreview`(`MarkdownContent`) |
200
+ | `txt` / `json` | `text_from_download` | 同上 | `TxtPreview`(`<pre>`) |
201
+ | 其余(如 `pdf` / `jpg`) | `preview_url_iframe` | `preview_url` | `UrlIframePreview`(`<iframe src>`,一般为后台转好的 PDF) |
202
+
203
+ > `md`(`AIFileType.Md`)为后台扩展名别名,与 `markdown`(`AIFileType.Markdown`)等价,共用 Markdown 直渲染。
204
+
205
+ ### 加载态
206
+
207
+ | status | 表现 |
208
+ | ------ | ---- |
209
+ | `loading` | 预览区 [MessageLoading](/components/helper/message-loading) |
210
+ | `ready` | 对应 renderer 渲染 |
211
+ | `empty` | 「暂无可预览的文件」(无文件 / 未传 `onArtifactClick` / 缺所需 URL) |
212
+ | `error` | 「预览加载失败」+ 重试按钮 |
213
+
214
+ 切换文件时 `useArtifactPreviewLoader` 用 `loadSeq` + `AbortController` 中断上一次 `fetch`,避免竞态覆盖。下载图标仍由面板用 bkui `Loading` spin 单独表达。
215
+
216
+ ## 内部结构(不导出)
217
+
218
+ ```
219
+ message-artifacts/
220
+ ├── file-artifact-panel.vue # 列表 + 下载头 + 挂载 Host
221
+ └── artifact-preview/
222
+ ├── artifact-preview-host.vue # 状态机 UI + 分派 renderer
223
+ ├── preview-strategy.ts # getArtifactPreviewStrategy
224
+ ├── use-artifact-preview-loader.ts
225
+ └── renderers/
226
+ ├── html-preview.vue
227
+ ├── markdown-preview.vue
228
+ ├── txt-preview.vue
229
+ └── url-iframe-preview.vue
230
+ ```
231
+
232
+ ## API
233
+
234
+ ### Props
235
+
236
+ | 属性名 | 类型 | 必填 | 说明 |
237
+ | --------- | ------------------- | ---- | -------------------------------------- |
238
+ | activeId | `string` | ✓ | 当前命中的文件 id(`messageUid#index#outputId`) |
239
+ | artifacts | `SessionArtifact[]` | ✓ | 当前会话全部文件产物 |
240
+
241
+ ### Events
242
+
243
+ | 事件名 | 参数 | 说明 |
244
+ | ------ | ----------------- | -------------------------- |
245
+ | select | `(id: string)` | 列表内切换选中文件,参数为文件 `artifactId` |
246
+
247
+ ### Slots / Expose
248
+
249
+ 无。
250
+
251
+ ## 类型定义
252
+
253
+ ```typescript
254
+ import type { AIFileInfo, SessionArtifact } from '@blueking/chat-x';
255
+
256
+ // 会话级文件产物:在 AIFileInfo 基础上补充命中所需字段
257
+ type SessionArtifact = AIFileInfo & {
258
+ artifactId: string; // 全局唯一 id:messageUid#index#outputId
259
+ messageUid: string; // 所属 AssistantMessage 的 uid
260
+ };
261
+
262
+ type AIFileInfo = {
263
+ name: string;
264
+ outputId: string;
265
+ size: number;
266
+ type: AIFileType;
267
+ };
268
+ ```
269
+
270
+ ## 关联 Composable
271
+
272
+ 预览**命中与取链**由 [useArtifactPreview](/composables/use-artifact-preview) 提供(Provider / Consumer + `ARTIFACT_PREVIEW_TOKEN`)。**正文加载与渲染**由内部 `useArtifactPreviewLoader` + `ArtifactPreviewHost` 完成,不在该 composable 内。
273
+
274
+ ## 关联组件
275
+
276
+ - [AssistantMessage](/components/message/assistant-message) — 文件产物来源(`property.artifacts`)
277
+ - [ChatContainer](/components/setup/chat-container) — 侧栏「文件产物」Tab 挂载场景,提供 `onArtifactClick`
278
+ - [MessageLoading](/components/helper/message-loading) — Host 预览区异步加载态
279
+ - [ExecutionSummary](/components/agent/execution-summary) — 同为侧栏 Tab 面板
@@ -11,13 +11,14 @@
11
11
  <!-- FULL DOC -->
12
12
 
13
13
  # InfoMessage 信息消息
14
+
14
15
  ## 源码事实
15
16
 
16
17
  - **源码位置**:`src/components/chat-message/info-message/info-message.vue`
17
18
  - **能力域**:消息系统
18
19
  - **能力说明**:渲染居中的系统信息提示。
19
20
 
20
- > **能力域**:消息系统
21
+ > **导出说明**:`InfoMessage` **未**从包入口导出(入口同名是 TS interface)。消费方经 `MessageRender` / `MessageContainer` 使用。下文 `InfoMessageComp` 为文档站内部示例。
21
22
 
22
23
  系统信息分隔组件,在聊天消息列表中以**居中虚线分隔条**的形式展示非对话类信息(会话重置、时间节点、状态变更等)。
23
24
 
@@ -35,13 +36,19 @@
35
36
 
36
37
  ```vue
37
38
  <template>
38
- <InfoMessage :content="content" />
39
+ <MessageRender :message="message" />
39
40
  </template>
40
41
 
41
42
  <script setup lang="ts">
42
- import { InfoMessage } from '@blueking/chat-x';
43
-
44
- const content = '以下是新的对话';
43
+ import { MessageRender, MessageRole, MessageStatus } from '@blueking/chat-x';
44
+
45
+ const message = {
46
+ id: '1',
47
+ messageId: '1',
48
+ role: MessageRole.Info,
49
+ content: '以下是新的对话',
50
+ status: MessageStatus.Complete,
51
+ };
45
52
  </script>
46
53
  ```
47
54
 
@@ -53,11 +60,20 @@
53
60
 
54
61
  ```vue
55
62
  <template>
56
- <InfoMessage :content="['会话已重置', '以下是新的对话']" />
63
+ <MessageRender :message="message" />
57
64
  </template>
58
65
 
59
66
  <script setup lang="ts">
60
- import { InfoMessage } from '@blueking/chat-x';
67
+ import { MessageRender, MessageRole, MessageStatus } from '@blueking/chat-x';
68
+
69
+ // 运行时 content 兼容 string[](TS 类型声明多为 string)
70
+ const message = {
71
+ id: '1',
72
+ messageId: '1',
73
+ role: MessageRole.Info,
74
+ content: ['会话已重置', '以下是新的对话'],
75
+ status: MessageStatus.Complete,
76
+ };
61
77
  </script>
62
78
  ```
63
79
 
@@ -32,6 +32,7 @@ ChatInput 底部附件区布局,承载快捷按钮、文件与发送图标。
32
32
  ### Slots
33
33
 
34
34
  - `default`
35
+ - `before-send`(发送按钮左侧区域,ChatInput 默认在此渲染 ModelSelector)
35
36
  - `send-icon`
36
37
 
37
38
  ### Expose
@@ -12,46 +12,60 @@
12
12
  <!-- FULL DOC -->
13
13
 
14
14
  # LoadingMessage 加载中消息
15
+
15
16
  ## 源码事实
16
17
 
17
18
  - **源码位置**:`src/components/chat-message/loading-message/loading-message.vue`
18
19
  - **能力域**:消息系统
19
20
  - **能力说明**:消息列表中的加载占位,默认使用 AiLoading,也支持默认插槽覆盖。
20
21
 
21
- > **能力域**:消息系统
22
+ > **导出说明**:`LoadingMessage` **未**从包入口导出。消费方经 `MessageRender`(`role: 'loading'`)或由 `MessageContainer` 自动注入。下文 `LoadingMessageComp` 为文档站内部示例。
22
23
 
23
- 加载等待状态组件,展示 AI 正在处理请求时的过渡动画。由旋转渐变环 + 脉冲星形图标(蓝→紫→粉渐变)和"请求中..."文案组成。支持通过默认插槽自定义加载文案。
24
+ 加载等待状态组件:`AiLoading`(18px)+ 默认文案「请求中...」。可通过默认插槽自定义文案。
24
25
 
25
- > **提示**:此组件通常**不需要手动使用**,`MessageContainer` 会在满足条件时自动注入。
26
+ > **提示**:通常**不需要手动使用**,`MessageContainer` / `useMessageGroup` 会在满足条件时自动注入。
26
27
 
27
28
  ## 渲染效果
28
29
 
29
30
  ## 基础用法
30
31
 
31
- 组件无 Props,直接引入渲染即可:
32
+ 组件无 Props。文档站内部示例:
33
+
34
+ ```vue
35
+ <template>
36
+ <LoadingMessageComp />
37
+ </template>
38
+ ```
39
+
40
+ 消费方经 `MessageRender`:
32
41
 
33
42
  ```vue
34
43
  <template>
35
- <LoadingMessage />
44
+ <MessageRender
45
+ :message="{
46
+ id: 'loading',
47
+ messageId: '',
48
+ role: MessageRole.Loading,
49
+ content: '',
50
+ status: MessageStatus.Pending,
51
+ }"
52
+ />
36
53
  </template>
37
54
 
38
55
  <script setup lang="ts">
39
- import { LoadingMessage } from '@blueking/chat-x';
56
+ import { MessageRender, MessageRole, MessageStatus } from '@blueking/chat-x';
40
57
  </script>
41
58
  ```
42
59
 
43
60
  ## 自定义加载文案
44
61
 
45
- 通过默认插槽可覆盖默认的"请求中..."文案:
62
+ 通过默认插槽覆盖「请求中...」:
46
63
 
47
64
  ```vue
48
65
  <template>
49
- <LoadingMessage>正在思考中,请稍候...</LoadingMessage>
66
+ <!-- 文档站内部示例 -->
67
+ <LoadingMessageComp>正在思考中,请稍候...</LoadingMessageComp>
50
68
  </template>
51
-
52
- <script setup lang="ts">
53
- import { LoadingMessage } from '@blueking/chat-x';
54
- </script>
55
69
  ```
56
70
 
57
71
  ## 动画说明
@@ -67,15 +81,18 @@
67
81
 
68
82
  ## 在 MessageContainer 中的自动注入
69
83
 
70
- `MessageContainer` 在构建消息分组列表时,检测到**消息列表最后一条为用户消息**(`role === 'user'`)时,自动在末尾追加一个 Loading 消息组:
84
+ `useMessageGroup` 构建分组时,若**最后一条为用户消息**且 **`renderMode !== RenderMode.Share`**,自动在末尾追加 Loading 组:
71
85
 
72
86
  ```typescript
73
- // MessageContainer 内部逻辑(简化)
74
- if (messages.at(-1)?.role === MessageRole.User) {
87
+ // use-message-group.ts(简化)
88
+ const shouldAppendLoading =
89
+ messages.at(-1)?.role === MessageRole.User && renderMode !== RenderMode.Share;
90
+
91
+ if (shouldAppendLoading) {
75
92
  list.push({
76
93
  messages: [
77
94
  {
78
- role: MessageRole.Loading, // 'loading'
95
+ role: MessageRole.Loading,
79
96
  content: '',
80
97
  status: MessageStatus.Pending,
81
98
  id: 'loading',
@@ -87,7 +104,8 @@ if (messages.at(-1)?.role === MessageRole.User) {
87
104
  }
88
105
  ```
89
106
 
90
- 当下一条 AI 消息(`role: 'assistant'`)到来后,最后一条不再是用户消息,Loading 组自动消失。
107
+ - 下一条 AI 消息到来后,末尾不再是 user,Loading 组自动消失
108
+ - **分享预览**(`renderMode === RenderMode.Share`)**不会**注入 Loading,避免分享页出现「请求中」占位
91
109
 
92
110
  **触发示例**:
93
111
 
@@ -127,6 +145,7 @@ if (messages.at(-1)?.role === MessageRole.User) {
127
145
  - **默认插槽**:可通过默认插槽自定义加载文案,未传入时显示内置的 "请求中..."
128
146
  - **i18n 支持**:默认文案 "请求中..." 通过内置 `t()` 函数处理,英文环境自动显示 "Requesting..."
129
147
  - **选择模式**:`MessageContainer` 开启 `enableSelection` 时,Loading 消息组不显示复选框
148
+ - **分享模式**:`renderMode === RenderMode.Share` 时不自动注入 Loading
130
149
  - **自动生命周期**:Loading 组随消息列表变化自动插入/移除,无需手动控制
131
150
 
132
151
  ## API
@@ -301,6 +301,51 @@ AI 回复状态为 `error` 时,消息以错误样式展示:
301
301
 
302
302
  连续多轮问答,组件按角色自动分组,每个 AI 组独立显示工具栏:
303
303
 
304
+ ## 自定义消息工具栏
305
+
306
+ `messageTools`(左侧)与 `updateTools`(右侧反馈区)用于在**内置工具的基础上做增量定制**,无需重写整份列表。二者分别与内置 `CONST_MESSAGE_TOOLS`、`CONST_UPDATE_TOOLS` 按 `id` 合并,规则如下:
307
+
308
+ - **覆盖**:`id` 命中内置项时,做字段级浅合并(仅覆盖传入的字段,其余保留),不新增条目
309
+ - **追加**:`id` 为内置列表中不存在的新值时,追加到该组末尾(如自定义「保存」「收藏」按钮)
310
+ - **隐藏**:传入 `{ id: 'xxx', hidden: true }` 可移除对应内置项(如隐藏「分享」)
311
+ - **自定义图标**:通过 `icon`(组件/VNode)为自定义按钮提供图标,优先级高于内置 `ToolIconsMap`
312
+ - 不传 `messageTools` / `updateTools` 时,各自使用内置默认列表
313
+
314
+ ```vue
315
+ <template>
316
+ <MessageContainer
317
+ :messages="messages"
318
+ :message-groups="messageGroups"
319
+ message-status="complete"
320
+ :message-tools="customMessageTools"
321
+ :update-tools="customUpdateTools"
322
+ :on-agent-action="handleAgentAction"
323
+ @stop-streaming="handleStopStreaming"
324
+ />
325
+ </template>
326
+
327
+ <script setup lang="ts">
328
+ import { MessageContainer, DownloadIcon, type IToolBtn, type Message } from '@blueking/chat-x';
329
+
330
+ const customMessageTools: IToolBtn[] = [
331
+ { id: 'save', name: '保存', description: '保存该回答', icon: DownloadIcon }, // 追加新按钮
332
+ { id: 'copy', description: '复制全文' }, // 覆盖内置 copy 的 description
333
+ { id: 'share', hidden: true }, // 隐藏内置「分享」
334
+ ];
335
+ const customUpdateTools: IToolBtn[] = [
336
+ { id: 'collect', name: '收藏', description: '收藏到我的空间', icon: DownloadIcon },
337
+ ];
338
+
339
+ const handleAgentAction = async (tool: IToolBtn, messages: Message[]) => {
340
+ if (tool.id === 'save') {
341
+ // 处理保存
342
+ }
343
+ };
344
+ </script>
345
+ ```
346
+
347
+ > **合并优先级**:`RenderMode.Test` 下仍会额外过滤掉「分享」按钮(即便合并后存在);即测试模式对 `share` 的过滤在自定义合并之后生效。
348
+
304
349
  ## 工具栏状态控制
305
350
 
306
351
  通过 `messageToolsStatus` 控制消息工具栏的显示状态。常见用法:流式输出期间禁用工具栏:
@@ -501,6 +546,8 @@ AI 回复状态为 `error` 时,消息以错误样式展示:
501
546
  | messages | `Message[]` | — | **必填**,消息列表 |
502
547
  | messageGroups | `MessageGroup[]` | — | 预计算的消息分组;传入时跳过内部分组逻辑,由 `ChatContainer` 通过 `useMessageGroup` 提供 |
503
548
  | messageStatus | `MessageStatus` | — | 当前整体消息状态,控制底部「停止生成」按钮显示;`ChatContainer` 会结合末尾 Loading 占位推导 `fetching` 等再传入 |
549
+ | messageTools | `IToolBtn[]` | — | AI 消息左侧工具(复制/引用等)的自定义配置;按 `id` 与内置 `CONST_MESSAGE_TOOLS` 合并(覆盖同 id、追加新 id、`hidden` 过滤),详见「自定义消息工具栏」 |
550
+ | updateTools | `IToolBtn[]` | — | AI 消息右侧反馈工具(点赞/踩/删除等)的自定义配置;按 `id` 与内置 `CONST_UPDATE_TOOLS` 合并,规则同上 |
504
551
  | messageToolsStatus | `MessageToolsStatus` | — | 工具栏状态,透传给 `MessageTools` 和 `MessageRender` |
505
552
  | messageToolsTippyOptions | `AITippyProps` | — | 透传给 `MessageTools` 和 `MessageRender`(进而透传给 `UserMessage` 的工具栏)的 Tippy 配置,用于自定义 tooltip 挂载点、位置等(如 `appendTo`、`placement`、`zIndex`) |
506
553
  | enableSelection | `boolean` | `false` | 是否启用多选模式 |