@blueking/chat-x 0.0.5 → 0.0.7

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 (85) hide show
  1. package/dist/components/ai-selection/ai-selection.vue.d.ts +2 -2
  2. package/dist/components/index.d.ts +2 -1
  3. package/dist/index.css +1 -1
  4. package/dist/index.js +6 -6
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp/generated/docs/activity-message.md +428 -0
  7. package/dist/mcp/generated/docs/ai-image.md +227 -0
  8. package/dist/mcp/generated/docs/ai-loading.md +129 -0
  9. package/dist/mcp/generated/docs/ai-selection.md +436 -0
  10. package/dist/mcp/generated/docs/animation-text.md +199 -0
  11. package/dist/mcp/generated/docs/assistant-message.md +424 -0
  12. package/dist/mcp/generated/docs/chat-container.md +402 -0
  13. package/dist/mcp/generated/docs/chat-input.md +625 -0
  14. package/dist/mcp/generated/docs/cite-content.md +138 -0
  15. package/dist/mcp/generated/docs/code-content.md +199 -0
  16. package/dist/mcp/generated/docs/common-error-content.md +70 -0
  17. package/dist/mcp/generated/docs/constants.md +216 -0
  18. package/dist/mcp/generated/docs/content-render.md +238 -0
  19. package/dist/mcp/generated/docs/delete-tool.md +188 -0
  20. package/dist/mcp/generated/docs/desc-panel.md +139 -0
  21. package/dist/mcp/generated/docs/execution-summary.md +126 -0
  22. package/dist/mcp/generated/docs/file-content.md +300 -0
  23. package/dist/mcp/generated/docs/file-upload-btn.md +174 -0
  24. package/dist/mcp/generated/docs/flow-message.md +305 -0
  25. package/dist/mcp/generated/docs/highlight-keyword.md +144 -0
  26. package/dist/mcp/generated/docs/image-content.md +178 -0
  27. package/dist/mcp/generated/docs/image-preview-group.md +181 -0
  28. package/dist/mcp/generated/docs/image-preview.md +224 -0
  29. package/dist/mcp/generated/docs/info-message.md +124 -0
  30. package/dist/mcp/generated/docs/key-value-content.md +124 -0
  31. package/dist/mcp/generated/docs/latex-content.md +196 -0
  32. package/dist/mcp/generated/docs/loading-message.md +171 -0
  33. package/dist/mcp/generated/docs/markdown-content.md +186 -0
  34. package/dist/mcp/generated/docs/markdown-latex.md +208 -0
  35. package/dist/mcp/generated/docs/markdown-mermaid.md +250 -0
  36. package/dist/mcp/generated/docs/mermaid-content.md +185 -0
  37. package/dist/mcp/generated/docs/message-container.md +534 -0
  38. package/dist/mcp/generated/docs/message-render.md +329 -0
  39. package/dist/mcp/generated/docs/message-tools.md +376 -0
  40. package/dist/mcp/generated/docs/messages.md +472 -0
  41. package/dist/mcp/generated/docs/overflow-tips.md +209 -0
  42. package/dist/mcp/generated/docs/reasoning-message.md +233 -0
  43. package/dist/mcp/generated/docs/reference-content.md +132 -0
  44. package/dist/mcp/generated/docs/scroll-btn.md +155 -0
  45. package/dist/mcp/generated/docs/selection-footer.md +75 -0
  46. package/dist/mcp/generated/docs/shortcut-btn.md +202 -0
  47. package/dist/mcp/generated/docs/shortcut-btns.md +264 -0
  48. package/dist/mcp/generated/docs/shortcut-render.md +418 -0
  49. package/dist/mcp/generated/docs/text-content.md +74 -0
  50. package/dist/mcp/generated/docs/theme.md +388 -0
  51. package/dist/mcp/generated/docs/tool-btn.md +254 -0
  52. package/dist/mcp/generated/docs/tool-message.md +217 -0
  53. package/dist/mcp/generated/docs/toolcall-render.md +299 -0
  54. package/dist/mcp/generated/docs/use-animation-text.md +198 -0
  55. package/dist/mcp/generated/docs/use-clipboard.md +206 -0
  56. package/dist/mcp/generated/docs/use-command-selection.md +128 -0
  57. package/dist/mcp/generated/docs/use-container-scroll.md +56 -0
  58. package/dist/mcp/generated/docs/use-custom-tab.md +122 -0
  59. package/dist/mcp/generated/docs/use-global-config.md +154 -0
  60. package/dist/mcp/generated/docs/use-menu-keydown.md +164 -0
  61. package/dist/mcp/generated/docs/use-message-group.md +175 -0
  62. package/dist/mcp/generated/docs/use-observer-visible-list.md +189 -0
  63. package/dist/mcp/generated/docs/use-parent-scrolling.md +46 -0
  64. package/dist/mcp/generated/docs/user-feedback.md +229 -0
  65. package/dist/mcp/generated/docs/user-message.md +347 -0
  66. package/dist/mcp/generated/index.json +1311 -0
  67. package/dist/mcp/index.d.ts +2 -0
  68. package/dist/mcp/index.js +42 -0
  69. package/dist/mcp/index.js.map +1 -0
  70. package/dist/mcp/server.d.ts +2 -0
  71. package/dist/mcp/server.js +43 -0
  72. package/dist/mcp/server.js.map +1 -0
  73. package/dist/mcp/tools/get-component-doc.d.ts +19 -0
  74. package/dist/mcp/tools/get-component-doc.js +60 -0
  75. package/dist/mcp/tools/get-component-doc.js.map +1 -0
  76. package/dist/mcp/tools/list-components.d.ts +35 -0
  77. package/dist/mcp/tools/list-components.js +147 -0
  78. package/dist/mcp/tools/list-components.js.map +1 -0
  79. package/dist/mcp/tools/search-docs.d.ts +14 -0
  80. package/dist/mcp/tools/search-docs.js +82 -0
  81. package/dist/mcp/tools/search-docs.js.map +1 -0
  82. package/dist/mcp/utils/doc-loader.d.ts +35 -0
  83. package/dist/mcp/utils/doc-loader.js +64 -0
  84. package/dist/mcp/utils/doc-loader.js.map +1 -0
  85. package/package.json +5 -7
@@ -0,0 +1,534 @@
1
+ <!-- AI SUMMARY -->
2
+ ## 快速了解
3
+
4
+ MessageContainer 是消息列表的核心容器。接收父组件用 useMessageGroup 生成的 messageGroups 与 messageStatus, 内部通过 MessageRender 按组渲染消息。支持流式停止、自动滚动与返回底部、多选与工具栏,需配置 onAgentAction 处理复制/重试等;点赞点踩通过 onAgentFeedback 回传原因。通常与 ChatInput 组合成完整对话区。
5
+
6
+ ### 关联组件
7
+ - **message-render** — 按组渲染每条消息时委托 MessageRender
8
+ - **chat-input** — 常与 ChatInput 组合构成完整对话界面
9
+ - **loading-message** — 末尾为用户消息时自动追加 Loading 消息组
10
+
11
+ ---
12
+ <!-- FULL DOC -->
13
+
14
+ # MessageContainer 消息容器
15
+
16
+ > **层级**:分子组件 · **功能域**:消息展示
17
+
18
+ 消息列表容器组件,负责将原始的 `Message[]` 数组渲染为结构化的对话界面。核心能力:
19
+
20
+ - **消息分组**:将连续的非用户消息合并为一组,每组共享一个工具栏
21
+ - **Tool 消息关联**:自动将 `role: 'tool'` 消息注入到对应 Assistant 消息的 toolCall 中
22
+ - **Loading 自动注入**:末尾为用户消息时,自动追加 Loading 动画组
23
+ - **滚动管理**:流式输出时显示"停止生成",离开底部时显示"返回底部"
24
+ - **多选模式**:支持按消息组勾选,用户消息与 AI 回复联动选中
25
+
26
+ ## 基础用法
27
+
28
+ ```vue
29
+ <template>
30
+ <MessageContainer
31
+ :messages="messages"
32
+ message-status="complete"
33
+ :on-agent-action="handleAgentAction"
34
+ :on-agent-feedback="handleAgentFeedback"
35
+ :on-user-action="handleUserAction"
36
+ @stop-streaming="handleStopStreaming"
37
+ />
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import { ref } from 'vue';
42
+ import { MessageContainer, MessageRole, MessageStatus, type Message, type IToolBtn } from '@blueking/chat-x';
43
+
44
+ const messages = ref<Message[]>([
45
+ {
46
+ id: '1',
47
+ messageId: '1',
48
+ role: MessageRole.User,
49
+ content: '你好,请介绍一下 Vue 3',
50
+ status: MessageStatus.Complete,
51
+ },
52
+ {
53
+ id: '2',
54
+ messageId: '2',
55
+ role: MessageRole.Assistant,
56
+ content: 'Vue 3 是一个渐进式 JavaScript 框架...',
57
+ status: MessageStatus.Complete,
58
+ },
59
+ ]);
60
+
61
+ const handleAgentAction = async (tool: IToolBtn, messages: Message[]) => {
62
+ // copy 操作由 MessageContainer 内部处理,此处无需额外实现
63
+ if (tool.id === 'like' || tool.id === 'unlike') {
64
+ return ['回答准确', '信息全面', '表达清晰']; // 返回反馈原因列表
65
+ }
66
+ };
67
+ const handleAgentFeedback = (tool: IToolBtn, messages: Message[], reasonList: string[], otherReason: string) => {
68
+ console.log('反馈:', tool.id, reasonList, otherReason);
69
+ };
70
+ const handleUserAction = async (tool: IToolBtn, message: Message) => {
71
+ console.log('用户消息操作:', tool.id, message);
72
+ };
73
+ const handleStopStreaming = () => {
74
+ console.log('停止流式输出');
75
+ };
76
+ </script>
77
+ ```
78
+
79
+ **渲染效果**
80
+
81
+ ## 消息分组机制
82
+
83
+ `MessageContainer` 在内部通过 `watchEffect` 将 `messages` 数组转换为消息组列表(`MessageGroup[]`)。分组规则如下:
84
+
85
+ ```
86
+ ┌─────────────────────────────────────────────────────────────┐
87
+ │ messages 原始数组(按顺序处理) │
88
+ └──────────────────────────────┬──────────────────────────────┘
89
+
90
+ ┌────────────────┴────────────────┐
91
+ │ │
92
+ role === 'user' role === 'tool'
93
+ │ │
94
+ ① 先把已累积的 assistantMessages ② 通过 toolCallId 找到对应的
95
+ 推入 list 作为一组 AssistantMessage,将 tool
96
+ ② 当前 user 消息单独成一组 消息注入 toolCall.toolMessage,
97
+ 然后 continue(不单独渲染)
98
+
99
+ 其他 role(assistant / reasoning /
100
+ activity / info / loading 等)
101
+
102
+ ③ 累积到 assistantMessages
103
+ 等待 user 消息触发分组
104
+
105
+ ④ 遍历结束后,将剩余 assistantMessages 推入 list
106
+ 每个 assistant 组计算 pause 字段:
107
+ pause = assistantMessages.some(m => m.property?.extra?.pause)
108
+ ⑤ 如果最后一条消息 role === 'user' → 追加 Loading 消息组
109
+ ```
110
+
111
+ **关键细节**:
112
+
113
+ - `role: 'tool'` 消息**不会独立渲染**,而是被注入到对应 AssistantMessage 的 `toolCall.toolMessage` 字段
114
+ - 若 `toolMessage.error` 存在,AssistantMessage 的 `status` 会被强制设为 `MessageStatus.Error`
115
+ - `MessageTools` 工具栏只在 `type === 'assistant'` 的消息组底部渲染(不依赖鼠标悬停,始终可见),且满足以下条件时**不渲染**:
116
+ - 消息组的 `pause` 为 `true`(来源于 `message.property?.extra?.pause`)
117
+ - 多选模式(`enableSelection`)开启且消息组不是 Loading 类型
118
+ - Loading 消息组的 `type` 是 `MessageRole.Loading`,不显示工具栏和多选 Checkbox
119
+
120
+ ## 等待响应(Loading 自动注入)
121
+
122
+ 当 `messages` 末尾为 `role: 'user'` 时,自动追加 Loading 消息组,展示 AI 正在处理的加载动画:
123
+
124
+ ## 流式输出
125
+
126
+ `messageStatus` 为 `streaming` 时,底部固定区域显示「停止生成」按钮,点击后触发 `@stop-streaming` 事件。
127
+
128
+ 点击下方按钮体验完整的流式输出过程:
129
+
130
+ **流式输出完整示例**:
131
+
132
+ ```vue
133
+ <template>
134
+ <MessageContainer
135
+ :messages="messages"
136
+ :message-status="messageStatus"
137
+ :on-agent-action="handleAgentAction"
138
+ :on-agent-feedback="handleAgentFeedback"
139
+ :on-user-action="handleUserAction"
140
+ @stop-streaming="handleStopStreaming"
141
+ />
142
+ </template>
143
+
144
+ <script setup lang="ts">
145
+ import { ref } from 'vue';
146
+ import { MessageContainer, MessageRole, MessageStatus, type Message, type IToolBtn } from '@blueking/chat-x';
147
+
148
+ const messageStatus = ref<MessageStatus>(MessageStatus.Complete);
149
+ const messages = ref<Message[]>([]);
150
+
151
+ const sendMessage = async (userInput: string) => {
152
+ // 1. 推入用户消息
153
+ messages.value.push({
154
+ id: Date.now().toString(),
155
+ messageId: Date.now().toString(),
156
+ role: MessageRole.User,
157
+ content: userInput,
158
+ status: MessageStatus.Complete,
159
+ });
160
+
161
+ // 2. 推入空 assistant 消息(触发 Loading 消失)
162
+ const assistantMsg: Message = {
163
+ id: (Date.now() + 1).toString(),
164
+ messageId: (Date.now() + 1).toString(),
165
+ role: MessageRole.Assistant,
166
+ content: '',
167
+ status: MessageStatus.Pending,
168
+ };
169
+ messages.value.push(assistantMsg);
170
+ messageStatus.value = MessageStatus.Streaming;
171
+
172
+ // 3. 逐步追加流式内容
173
+ for await (const chunk of fetchStream(userInput)) {
174
+ assistantMsg.content += chunk;
175
+ assistantMsg.status = MessageStatus.Streaming;
176
+ }
177
+
178
+ // 4. 标记完成
179
+ assistantMsg.status = MessageStatus.Complete;
180
+ messageStatus.value = MessageStatus.Complete;
181
+ };
182
+
183
+ const handleStopStreaming = () => {
184
+ messageStatus.value = MessageStatus.Stop;
185
+ const last = messages.value.at(-1);
186
+ if (last) last.status = MessageStatus.Stop;
187
+ };
188
+
189
+ const handleAgentAction = async (tool: IToolBtn, messages: Message[]) => {
190
+ if (tool.id === 'like' || tool.id === 'unlike') {
191
+ return ['回答准确', '信息全面'];
192
+ }
193
+ };
194
+ const handleAgentFeedback = (tool: IToolBtn, messages: Message[], reasonList: string[], otherReason: string) => {
195
+ console.log('反馈:', tool.id, reasonList);
196
+ };
197
+ const handleUserAction = async (tool: IToolBtn, message: Message) => {};
198
+ </script>
199
+ ```
200
+
201
+ ## 错误状态
202
+
203
+ AI 回复状态为 `error` 时,消息以错误样式展示:
204
+
205
+ ## 推理过程消息
206
+
207
+ `role: 'reasoning'` 消息会被归入当前 AI 消息组,带有折叠/展开效果和思考耗时展示:
208
+
209
+ ```vue
210
+ <script setup lang="ts">
211
+ const messages = ref<Message[]>([
212
+ {
213
+ id: '1',
214
+ messageId: '1',
215
+ role: MessageRole.User,
216
+ content: '分析一下这段代码的问题',
217
+ status: MessageStatus.Complete,
218
+ },
219
+ {
220
+ id: '2',
221
+ messageId: '2',
222
+ role: MessageRole.Reasoning,
223
+ content: ['首先,我需要理解代码意图...', '看起来是数据处理函数...', '发现几个潜在问题...'],
224
+ status: MessageStatus.Complete,
225
+ duration: 3500,
226
+ },
227
+ {
228
+ id: '3',
229
+ messageId: '3',
230
+ role: MessageRole.Assistant,
231
+ content: '根据分析,存在以下问题:\n\n1. 变量命名不规范...',
232
+ status: MessageStatus.Complete,
233
+ },
234
+ ]);
235
+ </script>
236
+ ```
237
+
238
+ **渲染效果**
239
+
240
+ ## 工具调用消息
241
+
242
+ `role: 'tool'` 消息通过 `toolCallId` 与对应 AssistantMessage 关联,被注入到 `toolCall.toolMessage` 后不再独立渲染:
243
+
244
+ ```vue
245
+ <script setup lang="ts">
246
+ const messages = ref<Message[]>([
247
+ { id: '1', messageId: '1', role: MessageRole.User, content: '查询北京天气', status: MessageStatus.Complete },
248
+ {
249
+ id: '2',
250
+ messageId: '2',
251
+ role: MessageRole.Assistant,
252
+ content: '好的,我来帮你查询。',
253
+ status: MessageStatus.Complete,
254
+ toolCalls: [
255
+ {
256
+ id: 'call_weather',
257
+ type: 'function',
258
+ function: { name: 'get_weather', arguments: '{"city": "北京"}', description: '查询天气信息' },
259
+ },
260
+ ],
261
+ },
262
+ // role: 'tool' 消息通过 toolCallId 关联到上方 assistant 消息
263
+ {
264
+ id: '3',
265
+ messageId: '3',
266
+ role: MessageRole.Tool,
267
+ content: '{"temperature":25,"weather":"晴天"}',
268
+ status: MessageStatus.Complete,
269
+ toolCallId: 'call_weather',
270
+ duration: 1200,
271
+ },
272
+ {
273
+ id: '4',
274
+ messageId: '4',
275
+ role: MessageRole.Assistant,
276
+ content: '北京今天 **晴朗**,温度 **25°C**。',
277
+ status: MessageStatus.Complete,
278
+ },
279
+ ]);
280
+ </script>
281
+ ```
282
+
283
+ **渲染效果**
284
+
285
+ ## Activity 知识检索消息
286
+
287
+ `role: 'activity'` 消息同样被归入 AI 消息组,与 assistant 消息一起渲染:
288
+
289
+ ## 多轮对话
290
+
291
+ 连续多轮问答,组件按角色自动分组,每个 AI 组独立显示工具栏:
292
+
293
+ ## 工具栏状态控制
294
+
295
+ 通过 `messageToolsStatus` 控制消息工具栏的显示状态。常见用法:流式输出期间禁用工具栏:
296
+
297
+ ```vue
298
+ <script setup lang="ts">
299
+ import { computed, ref } from 'vue';
300
+ import { MessageContainer, MessageStatus, MessageToolsStatus } from '@blueking/chat-x';
301
+
302
+ const messageStatus = ref(MessageStatus.Complete);
303
+
304
+ // 流式输出期间禁用工具栏,完成后恢复
305
+ const messageToolsStatus = computed(() =>
306
+ messageStatus.value === MessageStatus.Streaming ? MessageToolsStatus.Disabled : undefined,
307
+ );
308
+ </script>
309
+ ```
310
+
311
+ **三种状态对比**
312
+
313
+ | 状态值 | 说明 |
314
+ | ----------- | ------------------------------ |
315
+ | `undefined` | 默认,工具栏正常可用 |
316
+ | `disabled` | 工具栏显示但所有按钮不可点击 |
317
+ | `hidden` | 工具栏(`MessageTools`)不渲染 |
318
+
319
+ > **注意**:`messageToolsStatus` 同时透传给 `MessageRender`,控制用户消息中编辑、删除等按钮的状态。
320
+
321
+ ## 消息多选
322
+
323
+ 启用 `enableSelection` 后,每个消息组前显示 Checkbox,选中状态联动关联:
324
+
325
+ ```vue
326
+ <template>
327
+ <MessageContainer
328
+ v-model:selected-user-messages="selectedUserMessages"
329
+ :messages="messages"
330
+ :message-status="messageStatus"
331
+ :enable-selection="true"
332
+ :on-agent-action="handleAgentAction"
333
+ :on-user-action="handleUserAction"
334
+ @stop-streaming="handleStopStreaming"
335
+ />
336
+ <div v-if="selectedUserMessages.length > 0">
337
+ 已选择 {{ selectedUserMessages.length }} 条消息
338
+ <button @click="selectedUserMessages = []">清空选择</button>
339
+ </div>
340
+ </template>
341
+ ```
342
+
343
+ **多选特性**:
344
+
345
+ - `v-model:selected-user-messages` 仅包含选中的用户消息
346
+ - 选中用户消息组 → 其后紧邻的 AI 回复组视觉联动选中
347
+ - 选中 AI 回复组 → 其前紧邻的用户消息组联动选中
348
+ - 取消任一关联组 → 另一组同时取消
349
+ - 选中时消息组背景色变为 `#f5f7fa`
350
+ - 多选模式下用户消息工具栏自动隐藏
351
+ - Loading 消息组不显示 Checkbox
352
+
353
+ **渲染效果**(点击 Checkbox 体验多选)
354
+
355
+ ## 自定义消息渲染
356
+
357
+ 使用默认插槽替换单条消息的渲染,插槽参数包含 `message` 和 `messageToolsStatus`:
358
+
359
+ ```vue
360
+ <template>
361
+ <MessageContainer
362
+ :messages="messages"
363
+ :message-status="messageStatus"
364
+ :on-agent-action="handleAgentAction"
365
+ :on-user-action="handleUserAction"
366
+ @stop-streaming="handleStopStreaming"
367
+ >
368
+ <template #default="{ message, messageToolsStatus }">
369
+ <MyCustomMessage
370
+ :message="message"
371
+ :message-tools-status="messageToolsStatus"
372
+ />
373
+ </template>
374
+ </MessageContainer>
375
+ </template>
376
+ ```
377
+
378
+ > 使用默认插槽后,每条消息由自定义组件完全接管渲染,但**消息分组逻辑和工具栏(`MessageTools`)仍由 `MessageContainer` 管理**。
379
+
380
+ ## 自定义工具栏 Tooltip 配置
381
+
382
+ 通过 `messageToolsTippyOptions` 可以自定义消息工具栏中按钮 tooltip 的 Tippy 配置,透传给所有 `ToolBtn`。典型用法是修改 `appendTo` 避免 tooltip 被父容器 `overflow: hidden` 遮挡:
383
+
384
+ ```vue
385
+ <template>
386
+ <!-- tooltip 挂载到触发元素的父节点,避免被滚动容器裁剪 -->
387
+ <MessageContainer
388
+ :messages="messages"
389
+ :message-tools-tippy-options="{ appendTo: 'parent' }"
390
+ :on-agent-action="handleAgentAction"
391
+ @stop-streaming="handleStopStreaming"
392
+ />
393
+ </template>
394
+ ```
395
+
396
+ > **注意**:`content`、`getReferenceClientRect`、`triggerTarget` 三个字段被排除,不可通过此 prop 覆盖。
397
+
398
+ ## 用户消息编辑与快捷指令
399
+
400
+ 通过 `onUserInputConfirm` 和 `onUserShortcutConfirm` 处理用户消息的编辑确认和快捷指令表单提交:
401
+
402
+ ```vue
403
+ <template>
404
+ <MessageContainer
405
+ :messages="messages"
406
+ :message-status="messageStatus"
407
+ :on-agent-action="handleAgentAction"
408
+ :on-user-action="handleUserAction"
409
+ :on-user-input-confirm="handleUserInputConfirm"
410
+ :on-user-shortcut-confirm="handleUserShortcutConfirm"
411
+ @stop-streaming="handleStopStreaming"
412
+ />
413
+ </template>
414
+
415
+ <script setup lang="ts">
416
+ import { MessageContainer, type Message, type TagSchema } from '@blueking/chat-x';
417
+
418
+ // 用户点击编辑并确认时触发
419
+ const handleUserInputConfirm = async (message: Message, content: UserMessage['content'], docSchema: TagSchema) => {
420
+ // message: 原始消息对象
421
+ // content: 编辑后的内容(字符串或富文本结构)
422
+ // docSchema: 引用文档结构
423
+ console.log('用户编辑确认:', message.id, content);
424
+ };
425
+
426
+ // 用户提交快捷指令表单时触发
427
+ const handleUserShortcutConfirm = async (message: Message, formModel: Record<string, unknown>) => {
428
+ console.log('快捷指令提交:', message.id, formModel);
429
+ };
430
+ </script>
431
+ ```
432
+
433
+ ## copy 操作内置处理
434
+
435
+ `MessageContainer` 内部对 `copy` 工具操作进行了特殊处理:当 `tool.id === 'copy'` 时,自动将当前消息组中所有**非 reasoning 消息**的内容拼接后复制到剪贴板,**无需在 `onAgentAction` 中自行实现**。
436
+
437
+ 其他工具操作(`like`、`unlike`、`cite` 等)仍正常转发给 `onAgentAction` 回调。
438
+
439
+ ## 滚动控制
440
+
441
+ 底部固定区域(`position: sticky; bottom: 12px`)根据条件显示两个按钮:
442
+
443
+ | 按钮 | 显示条件 | 点击行为 |
444
+ | ------------ | ---------------------------------------------------------------------------- | ---------------------- |
445
+ | 「停止生成」 | `messageStatus === 'streaming'` | 触发 `@stop-streaming` |
446
+ | 「返回底部」 | `debouncedShowScrollBottomBtn`(距底部 > 100px,且防抖 300ms 后才显示/隐藏) | 滚动到消息列表底部 |
447
+
448
+ > **防抖说明**:「返回底部」按钮的显隐使用 300ms 防抖,避免快速滚动时按钮频繁闪烁。隐藏时立即生效(无防抖),显示时延迟 300ms。
449
+
450
+ ## API
451
+
452
+ ### Props
453
+
454
+ | 属性名 | 类型 | 默认值 | 说明 |
455
+ | ------------------------ | -------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
456
+ | messages | `Message[]` | — | **必填**,消息列表 |
457
+ | messageGroups | `MessageGroup[]` | — | 预计算的消息分组;传入时跳过内部分组逻辑,由 `ChatContainer` 通过 `useMessageGroup` 提供 |
458
+ | messageStatus | `MessageStatus` | — | 当前整体消息状态,控制停止生成按钮显示 |
459
+ | messageToolsStatus | `MessageToolsStatus` | — | 工具栏状态,透传给 `MessageTools` 和 `MessageRender` |
460
+ | messageToolsTippyOptions | `AITippyProps` | — | 透传给 `MessageTools` 和 `MessageRender`(进而透传给 `UserMessage` 的工具栏)的 Tippy 配置,用于自定义 tooltip 挂载点(如 `appendTo`)等 |
461
+ | enableSelection | `boolean` | `false` | 是否启用多选模式 |
462
+ | onAgentAction | `(tool: IToolBtn, messages: Message[]) => Promise<string[] \| void>` | — | AI 消息工具操作回调;`copy` 操作由内部处理,`like/unlike` 应返回反馈原因字符串数组 |
463
+ | onAgentFeedback | `(tool: IToolBtn, messages: Message[], reasonList: string[], otherReason: string) => void` | — | AI 消息反馈提交回调(点赞/踩选完原因后触发) |
464
+ | onUserAction | `(tool: IToolBtn, message: Message) => Promise<string[] \| void>` | — | 用户消息工具操作回调 |
465
+ | onUserInputConfirm | `(message: Message, content: UserMessage['content'], docSchema: TagSchema) => Promise<void>` | — | 用户编辑消息确认回调 |
466
+ | onUserShortcutConfirm | `(message: Message, formModel: Record<string, unknown>) => Promise<void>` | — | 用户快捷指令表单提交回调 |
467
+
468
+ ### v-model
469
+
470
+ | 属性名 | 类型 | 说明 |
471
+ | -------------------- | ----------- | -------------------------------------------------- |
472
+ | selectedUserMessages | `Message[]` | 当前选中的用户消息列表(双向绑定,仅包含用户消息) |
473
+
474
+ ### Events
475
+
476
+ | 事件名 | 参数 | 说明 |
477
+ | ------------- | ---- | -------------------------- |
478
+ | stopStreaming | — | 点击「停止生成」按钮时触发 |
479
+
480
+ ### Slots
481
+
482
+ | 插槽名 | 参数 | 说明 |
483
+ | ------- | --------------------------------------------------------------------------- | ------------------------------------------------ |
484
+ | default | `{ message: Message, messageToolsStatus: MessageToolsStatus \| undefined }` | 自定义单条消息渲染,消息分组和工具栏仍由容器管理 |
485
+
486
+ ## 类型定义
487
+
488
+ ```typescript
489
+ import { MessageRole, MessageStatus, MessageToolsStatus, type Message, type IToolBtn } from '@blueking/chat-x';
490
+
491
+ // onAgentAction 回调类型
492
+ // messages 为当前消息组全部消息(可含 reasoning / activity 等)
493
+ // 返回 string[] 时用作 like/unlike 的反馈原因列表
494
+ type AgentActionCallback = (tool: IToolBtn, messages: Message[]) => Promise<string[] | void>;
495
+
496
+ // onAgentFeedback 回调类型
497
+ type AgentFeedbackCallback = (tool: IToolBtn, messages: Message[], reasonList: string[], otherReason: string) => void;
498
+
499
+ // onUserAction 回调类型
500
+ type UserActionCallback = (tool: IToolBtn, message: Message) => Promise<string[] | void>;
501
+
502
+ // 工具栏状态
503
+ enum MessageToolsStatus {
504
+ Disabled = 'disabled',
505
+ Hidden = 'hidden',
506
+ }
507
+
508
+ // 消息角色
509
+ enum MessageRole {
510
+ User = 'user',
511
+ Assistant = 'assistant',
512
+ Tool = 'tool',
513
+ Reasoning = 'reasoning',
514
+ Activity = 'activity',
515
+ Info = 'info',
516
+ Loading = 'loading',
517
+ }
518
+
519
+ // 消息状态
520
+ enum MessageStatus {
521
+ Pending = 'pending',
522
+ Streaming = 'streaming',
523
+ Complete = 'complete',
524
+ Error = 'error',
525
+ Stop = 'stop',
526
+ Disabled = 'disabled',
527
+ }
528
+ ```
529
+
530
+ ## 关联组件
531
+
532
+ - [MessageRender](./message-render.md) — 按组渲染每条消息时委托使用
533
+ - [ChatInput](./chat-input.md) — 常与输入区组合构成完整对话界面
534
+ - [LoadingMessage](./loading-message.md) — 末尾为用户消息时自动追加加载组