@blueking/chat-x 0.0.48-beta.1 → 0.0.49-beta.10
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/constants.d.ts +1 -0
- package/dist/ag-ui/types/file.d.ts +13 -0
- package/dist/ag-ui/types/index.d.ts +1 -0
- package/dist/ag-ui/types/messages.d.ts +4 -0
- package/dist/components/chat-message/assistant-message/assistant-message.vue.d.ts +12 -1
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-file-card.vue.d.ts +12 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/artifact-preview-host.vue.d.ts +11 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/preview-strategy.d.ts +8 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/code-preview.vue.d.ts +8 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/html-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/image-preview.vue.d.ts +7 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/markdown-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/txt-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/renderers/url-iframe-preview.vue.d.ts +6 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/use-artifact-preview-loader.d.ts +22 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue.d.ts +13 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/message-artifacts.vue.d.ts +9 -0
- package/dist/components/chat-message/interrupt-message/user-question/use-user-question.d.ts +7 -2
- package/dist/components/chat-message/user-message/user-message.vue.d.ts +15 -2
- package/dist/components/file-icon/file-icon.vue.d.ts +7 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/components/message-tools/message-time/format-message-time.d.ts +8 -0
- package/dist/components/message-tools/message-time/message-time.vue.d.ts +8 -0
- package/dist/components/message-tools/message-tools.vue.d.ts +11 -1
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/use-artifact-preview.d.ts +49 -0
- package/dist/composables/use-container-scroll.d.ts +9 -2
- package/dist/composables/use-custom-tab.d.ts +7 -3
- package/dist/composables/use-global-config.d.ts +3 -0
- package/dist/composables/use-message-group.d.ts +505 -0
- package/dist/icons/file-icons.d.ts +4 -0
- package/dist/icons/file.d.ts +6 -0
- package/dist/icons/index.d.ts +2 -0
- package/dist/icons/tools.d.ts +3 -0
- package/dist/index.css +1 -1
- package/dist/index.js +3203 -2368
- package/dist/index.js.map +1 -1
- package/dist/lang/lang.d.ts +9 -1
- package/dist/mcp/generated/docs/activity-message.md +122 -97
- package/dist/mcp/generated/docs/assistant-message.md +146 -75
- package/dist/mcp/generated/docs/chat-container.md +121 -38
- package/dist/mcp/generated/docs/chat-input.md +2 -10
- package/dist/mcp/generated/docs/constants.md +3 -1
- package/dist/mcp/generated/docs/content-render.md +2 -10
- package/dist/mcp/generated/docs/execution-summary.md +3 -3
- package/dist/mcp/generated/docs/file-artifact-panel.md +293 -0
- package/dist/mcp/generated/docs/file-icon.md +111 -0
- package/dist/mcp/generated/docs/info-message.md +29 -12
- package/dist/mcp/generated/docs/interrupt.md +1 -0
- package/dist/mcp/generated/docs/loading-message.md +36 -17
- package/dist/mcp/generated/docs/message-container.md +27 -23
- package/dist/mcp/generated/docs/message-render.md +47 -59
- package/dist/mcp/generated/docs/message-time.md +180 -0
- package/dist/mcp/generated/docs/message-tools.md +47 -12
- package/dist/mcp/generated/docs/messages.md +9 -0
- package/dist/mcp/generated/docs/reasoning-message.md +17 -20
- package/dist/mcp/generated/docs/tool-message.md +61 -45
- package/dist/mcp/generated/docs/toolcall-render.md +18 -10
- package/dist/mcp/generated/docs/use-artifact-preview.md +234 -0
- package/dist/mcp/generated/docs/use-container-scroll.md +6 -2
- package/dist/mcp/generated/docs/use-custom-tab.md +25 -8
- package/dist/mcp/generated/docs/use-global-config.md +15 -5
- package/dist/mcp/generated/docs/use-message-group.md +37 -5
- package/dist/mcp/generated/docs/user-message.md +191 -121
- package/dist/mcp/generated/docs/user-question-card.md +6 -3
- package/dist/mcp/generated/index.json +144 -18
- package/dist/mcp/index.js +0 -0
- package/dist/utils/file-type.d.ts +14 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +20 -21
|
@@ -654,19 +654,11 @@ const handleSendMessage = async (
|
|
|
654
654
|
|
|
655
655
|
## 类型定义
|
|
656
656
|
|
|
657
|
+
> `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。与输入区相关:`pending` / `streaming` / `fetching` → 停止按钮;`complete` / `completed` / `error` / `stop` → 发送;`disabled` → 置灰。
|
|
658
|
+
|
|
657
659
|
```typescript
|
|
658
660
|
import type { UserMessage } from '@blueking/chat-x';
|
|
659
661
|
|
|
660
|
-
// 消息状态
|
|
661
|
-
enum MessageStatus {
|
|
662
|
-
Pending = 'pending', // 等待中(显示停止按钮)
|
|
663
|
-
Streaming = 'streaming', // 流式输出中(显示停止按钮)
|
|
664
|
-
Complete = 'complete', // 完成(显示发送按钮)
|
|
665
|
-
Error = 'error', // 错误(显示发送按钮)
|
|
666
|
-
Stop = 'stop', // 已停止(显示发送按钮)
|
|
667
|
-
Disabled = 'disabled', // 禁用(发送按钮置灰)
|
|
668
|
-
}
|
|
669
|
-
|
|
670
662
|
// 上传状态
|
|
671
663
|
enum UploadStatus {
|
|
672
664
|
Pending = 'pending', // 上传中
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- AI SUMMARY -->
|
|
2
2
|
## 快速了解
|
|
3
3
|
|
|
4
|
-
汇总 MessageRole、MessageStatus(含 Fetching
|
|
4
|
+
汇总 MessageRole、MessageStatus(含 Fetching 请求中、Complete/Completed 完成态兼容)、MessageContentType、MessageToolsStatus、MessageState、Z-Index 与 CONST_MESSAGE_TOOLS 等导出常量。 用于构造消息、配置 MessageContainer 工具栏与输入态,以及层级与默认快捷指令。与类型 messages 配套使用。
|
|
5
5
|
|
|
6
6
|
### 关联组件
|
|
7
7
|
- **message-tools** — 默认工具 ID 与展示
|
|
@@ -58,6 +58,7 @@ enum MessageRole {
|
|
|
58
58
|
```typescript
|
|
59
59
|
enum MessageStatus {
|
|
60
60
|
Complete = 'complete',
|
|
61
|
+
Completed = 'completed', // 与 Complete 同为完成态,兼容后端/协议返回的 completed
|
|
61
62
|
Disabled = 'disabled',
|
|
62
63
|
Error = 'error',
|
|
63
64
|
Fetching = 'fetching', // 请求中(例如已发用户消息、尚未开始流式,与末尾 Loading 占位一致)
|
|
@@ -71,6 +72,7 @@ enum MessageStatus {
|
|
|
71
72
|
|
|
72
73
|
| 枚举值 | 说明 |
|
|
73
74
|
| --------------- | ---- |
|
|
75
|
+
| `Complete` / `Completed` | 已完成。`complete` 为库内常用值;`completed` 与之语义相同,用于兼容外部协议或后端返回。`ToolcallRender` 等将二者与 `success` 一并视为成功态。 |
|
|
74
76
|
| `Fetching` | 请求中:与 `useMessageGroup` 在末尾用户消息后注入的 Loading 占位(`LOADING_MESSAGE_ID`)配合时,`ChatContainer` 会将传入输入区与列表底部的状态推导为该值,便于展示「停止」与禁止重复发送。 |
|
|
75
77
|
|
|
76
78
|
### InterruptReason
|
|
@@ -216,18 +216,10 @@ enum MessageContentType {
|
|
|
216
216
|
KnowledgeRag = 'knowledge_rag',
|
|
217
217
|
Other = 'other',
|
|
218
218
|
}
|
|
219
|
-
|
|
220
|
-
// 消息状态
|
|
221
|
-
enum MessageStatus {
|
|
222
|
-
Pending = 'pending',
|
|
223
|
-
Streaming = 'streaming',
|
|
224
|
-
Complete = 'complete',
|
|
225
|
-
Error = 'error',
|
|
226
|
-
Stop = 'stop',
|
|
227
|
-
Disabled = 'disabled',
|
|
228
|
-
}
|
|
229
219
|
```
|
|
230
220
|
|
|
221
|
+
> `MessageStatus` 完整取值见 [常量枚举](../../types/constants);本组件主要关心 `error`(错误内容)与流式相关状态。
|
|
222
|
+
|
|
231
223
|
## 使用场景
|
|
232
224
|
|
|
233
225
|
- **AI 文本回复渲染**:`AssistantMessage` 内部用 `ContentRender` 渲染 AI 回复内容,`status` 配合流式响应
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
```
|
|
64
64
|
ai-execution-summary
|
|
65
|
-
├── ai-execution-summary-header
|
|
65
|
+
├── ai-execution-summary-header(仅 messageGroups 非空时渲染)
|
|
66
66
|
│ └── Input(关键词搜索框,clearable)
|
|
67
67
|
└── ai-execution-summary-content
|
|
68
68
|
├── 有数据时:
|
|
@@ -73,12 +73,12 @@ ai-execution-summary
|
|
|
73
73
|
│ ├── content-item-messages(MessageRender × N)
|
|
74
74
|
│ └── timeline-line(连接线,最后一项不显示)
|
|
75
75
|
└── 无数据时:
|
|
76
|
-
└── Exception
|
|
76
|
+
└── Exception(scene="part")+「暂无数据」/「搜索结果为空」文案(有关键词时附带「清空搜索」)
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
## 空状态
|
|
80
80
|
|
|
81
|
-
当 `messageGroups`
|
|
81
|
+
当 `messageGroups` 为空数组时,**不渲染搜索 header**,内容区整块展示空态(bkui `Exception` +「暂无数据」;若仍有搜索关键词则为「搜索结果为空」并提供「清空搜索」):
|
|
82
82
|
|
|
83
83
|
## 与 ChatContainer 配合
|
|
84
84
|
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
汇总当前会话所有 AssistantMessage 的 artifacts(按 outputId 去重),支持关键词搜索、列表选中与下载; 预览区委托 ArtifactPreviewHost:由 resolveFileKind 把扩展名归入 code / markdown / html / text / image / binary 六类, 前四类走 text_from_download 拉正文(code 交给 highlight.js 高亮),image / binary 走 preview_url; download_url / preview_url 经 onArtifactClick 每次异步获取(无 URL 缓存,并发去重); 预览重载键为 outputId:type;重试再次调用 load() 重新取链。 源码位置: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` 的文件产物(按 `outputId` 去重),并命中被点击的文件进行预览。
|
|
26
|
+
|
|
27
|
+
面板左侧为可搜索的文件列表,右侧为预览区。通常不需要直接使用,由 `ChatContainer` 在侧栏内自动渲染。
|
|
28
|
+
|
|
29
|
+
## 核心能力
|
|
30
|
+
|
|
31
|
+
- **会话级聚合**:拍平当前会话所有 `AssistantMessage.property.artifacts`,以 `outputId` 去重后统一在一个列表内展示
|
|
32
|
+
- **唯一命中**:以 `outputId` 作为会话内唯一键(同 `outputId` 视为同一文件);文件名可能重复,不可作唯一键
|
|
33
|
+
- **关键词搜索**:按文件名实时过滤列表
|
|
34
|
+
- **整块空态**:`artifacts` 为空时不渲染列表与预览区,整块展示 bkui `Exception`「暂无数据」(Tab 常驻,无数据也可正常打开侧栏)
|
|
35
|
+
- **异步取链**:`AIFileInfo` 本身不含 `url` / `previewUrl`,通过 `ChatContainer` 的 `onArtifactClick` 按 `outputId` 获取 `download_url` / `preview_url`(TTL 8 分钟缓存;预览重试会 `force` 刷新)
|
|
36
|
+
- **职责拆分**:
|
|
37
|
+
- **面板本身**:列表、搜索、预览头(文件名 / 图标 / 下载)
|
|
38
|
+
- **`ArtifactPreviewHost`**:按策略加载正文或预览 URL,分派到对应 renderer;展示 loading / empty / error(含重试)
|
|
39
|
+
- **未传 `onArtifactClick`**:下载按钮隐藏,预览区展示无数据
|
|
40
|
+
|
|
41
|
+
## 基础用法
|
|
42
|
+
|
|
43
|
+
面板**未从包入口导出**,业务侧请走下方「业务接入」;下列示例仅用于文档站 / 本地调试(与 `ExecutionSummary` 文档站写法一致:相对路径引入 + 自行挂 Provider)。
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<template>
|
|
47
|
+
<div style="height: 480px; border: 1px solid #dcdee5; border-radius: 8px; overflow: hidden;">
|
|
48
|
+
<FileArtifactPanel
|
|
49
|
+
:active-id="activeArtifactId"
|
|
50
|
+
:artifacts="sessionArtifacts"
|
|
51
|
+
@select="handleSelect"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script setup lang="ts">
|
|
57
|
+
import { shallowRef } from 'vue'
|
|
58
|
+
import { useArtifactPreviewProvider } from '@blueking/chat-x'
|
|
59
|
+
import type { AIFileInfo, SessionArtifact } from '@blueking/chat-x'
|
|
60
|
+
// 内部组件:仅文档 / 调试;业务请用 ChatContainer 自动挂载
|
|
61
|
+
import FileArtifactPanel from './message-artifacts/file-artifact-panel.vue'
|
|
62
|
+
|
|
63
|
+
const sessionArtifacts: SessionArtifact[] = [
|
|
64
|
+
{ name: '周报.html', outputId: 'a-html', size: 10240, type: 'html' },
|
|
65
|
+
{ name: '说明.md', outputId: 'a-md', size: 8192, type: 'md' },
|
|
66
|
+
{ name: '纪要.txt', outputId: 'a-txt', size: 4096, type: 'txt' },
|
|
67
|
+
{ name: '配置.json', outputId: 'a-json', size: 2048, type: 'json' },
|
|
68
|
+
{ name: '立项.pdf', outputId: 'a-pdf', size: 204800, type: 'pdf' },
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
useArtifactPreviewProvider({
|
|
72
|
+
getOnArtifactClick: () => async file => {
|
|
73
|
+
// 文本类返回可 fetch 的 download_url;iframe 类返回 preview_url
|
|
74
|
+
const res = await api.getArtifactUrls(file.outputId)
|
|
75
|
+
return { download_url: res.download_url, preview_url: res.preview_url }
|
|
76
|
+
},
|
|
77
|
+
onOpen: () => {},
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const activeArtifactId = shallowRef(sessionArtifacts[0].outputId)
|
|
81
|
+
const handleSelect = (id: string) => {
|
|
82
|
+
activeArtifactId.value = id
|
|
83
|
+
}
|
|
84
|
+
</script>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**渲染效果**(点击左侧列表切换类型;文本类直渲染,PDF 走 iframe。Mock 取链约 600ms)
|
|
88
|
+
|
|
89
|
+
## 业务接入(ChatContainer)
|
|
90
|
+
|
|
91
|
+
日常用法是给容器传 `messages`(含 `property.artifacts`)与 `onArtifactClick`,点击文件卡片即可打开侧栏面板:
|
|
92
|
+
|
|
93
|
+
```vue
|
|
94
|
+
<template>
|
|
95
|
+
<ChatContainer
|
|
96
|
+
v-model="input"
|
|
97
|
+
:messages="messages"
|
|
98
|
+
:on-artifact-click="onArtifactClick"
|
|
99
|
+
@send-message="handleSend"
|
|
100
|
+
/>
|
|
101
|
+
</template>
|
|
102
|
+
|
|
103
|
+
<script setup lang="ts">
|
|
104
|
+
import { ref, shallowRef } from 'vue'
|
|
105
|
+
import {
|
|
106
|
+
ChatContainer,
|
|
107
|
+
MessageRole,
|
|
108
|
+
MessageStatus,
|
|
109
|
+
type AIFileInfo,
|
|
110
|
+
type Message,
|
|
111
|
+
} from '@blueking/chat-x'
|
|
112
|
+
|
|
113
|
+
const input = ref('')
|
|
114
|
+
const messages = shallowRef<Message[]>([
|
|
115
|
+
{
|
|
116
|
+
id: 'u1',
|
|
117
|
+
messageId: 'u1',
|
|
118
|
+
role: MessageRole.User,
|
|
119
|
+
status: MessageStatus.Complete,
|
|
120
|
+
content: '整理本周评审材料',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'a1',
|
|
124
|
+
messageId: 'a1',
|
|
125
|
+
uid: 'assistant-uid-1',
|
|
126
|
+
role: MessageRole.Assistant,
|
|
127
|
+
status: MessageStatus.Complete,
|
|
128
|
+
content: '已生成评审材料,点击卡片可在侧栏预览:',
|
|
129
|
+
property: {
|
|
130
|
+
artifacts: [
|
|
131
|
+
{ name: '周报.html', outputId: 'a-html', size: 10240, type: 'html' },
|
|
132
|
+
{ name: '说明.md', outputId: 'a-md', size: 8192, type: 'md' },
|
|
133
|
+
{ name: '配置.json', outputId: 'a-json', size: 2048, type: 'json' },
|
|
134
|
+
{ name: '立项.pdf', outputId: 'a-pdf', size: 204800, type: 'pdf' },
|
|
135
|
+
] satisfies AIFileInfo[],
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
])
|
|
139
|
+
|
|
140
|
+
const onArtifactClick = async (file: AIFileInfo) => {
|
|
141
|
+
const res = await api.getArtifactUrls(file.outputId)
|
|
142
|
+
return {
|
|
143
|
+
download_url: res.download_url,
|
|
144
|
+
preview_url: res.preview_url,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const handleSend = () => {
|
|
149
|
+
/* ... */
|
|
150
|
+
}
|
|
151
|
+
</script>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 触发链路
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
ArtifactFileCard(点击文件卡片)
|
|
158
|
+
└─ useArtifactPreviewConsumer().openPreview({ file })
|
|
159
|
+
└─ useArtifactPreviewProvider(ChatContainer 内)
|
|
160
|
+
├─ 记录命中文件 activeArtifactId = file.outputId
|
|
161
|
+
└─ onOpen → addCustomTab('file-artifact') 展开并选中侧栏 Tab
|
|
162
|
+
└─ FileArtifactPanel
|
|
163
|
+
├─ 列表 @select → setActiveArtifactId(outputId)
|
|
164
|
+
├─ 下载 → resolveArtifactUrls + triggerArtifactDownload
|
|
165
|
+
└─ ArtifactPreviewHost
|
|
166
|
+
├─ useArtifactPreviewLoader(策略 + fetch / 取链,防竞态)
|
|
167
|
+
└─ HtmlPreview | MarkdownPreview | TxtPreview | UrlIframePreview
|
|
168
|
+
|
|
169
|
+
容器初始化
|
|
170
|
+
└─ ensureCustomTab('file-artifact') 常驻挂上(不展开侧栏);因 order:-1 排在首位,
|
|
171
|
+
未主动切换过 Tab 时会成为默认选中面板;无产物时由面板展示整块空态
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- 文件卡片通过 `useArtifactPreviewConsumer` 注入预览上下文,无 Provider 时卡片不可点击(兜底 `undefined`)
|
|
175
|
+
- `ChatContainer` 通过 `useArtifactPreviewProvider` 提供上下文,并把「打开侧栏 Tab」这一副作用以 `onOpen` 注入,保持 composable 职责单一
|
|
176
|
+
- 侧栏「文件产物」Tab 固定不可关闭,`order: -1` 排在「执行情况」之前;**常驻不随产物有无增删**,无产物时由面板展示整块空态
|
|
177
|
+
|
|
178
|
+
## 唯一键规则
|
|
179
|
+
|
|
180
|
+
会话内以 **`outputId`** 作为文件产物唯一键:
|
|
181
|
+
|
|
182
|
+
- 同一 `outputId` 在多条消息中出现时,聚合列表去重并保留最后一次出现的文件信息
|
|
183
|
+
- `activeId`、列表 `:key`、`select` 事件参数均使用 `outputId`
|
|
184
|
+
- 文件名可能重复,**不可**作为唯一键
|
|
185
|
+
|
|
186
|
+
## 预览机制
|
|
187
|
+
|
|
188
|
+
预览分两步:先由 `resolveFileKind(type, name)`(`src/utils/file-type.ts`)把扩展名归入六个**分类**,再由 `getArtifactPreviewStrategy` 查表得到 **加载方式** 与 **渲染器**。面板与 Host 都不写死具体扩展名分支,后台新增文件类型时只需在分类表里补一行。
|
|
189
|
+
|
|
190
|
+
| 分类 | 覆盖扩展名 | load | 取链字段 | renderer |
|
|
191
|
+
| ---- | ---------- | ---- | -------- | -------- |
|
|
192
|
+
| `code` | `py` `js` `mjs` `cjs` `ts` `tsx` `jsx` `vue` `go` `rs` `rb` `java` `kt` `swift` `c` `h` `cpp` `hpp` `cs` `php` `lua` `r` `scala` `dart` `sh` `bash` `zsh` `ps1` `sql` `css` `scss` `less` `json` `jsonc` `yaml` `yml` `toml` `ini` `cfg` `conf` `env` `xml` `tex` `Dockerfile` `Makefile` `gitignore` `dockerignore` `editorconfig` | `text_from_download` | `download_url` → `fetch` 正文 | `CodePreview`(highlight.js 高亮) |
|
|
193
|
+
| `markdown` | `md` `markdown` | `text_from_download` | 同上 | `MarkdownPreview`(`MarkdownContent`) |
|
|
194
|
+
| `html` | `html` `htm` | `text_from_download` | 同上 | `HtmlPreview`(`<iframe srcdoc>`) |
|
|
195
|
+
| `text` | `txt` `rst` | `text_from_download` | 同上 | `TxtPreview`(`<pre>`) |
|
|
196
|
+
| `image` | `png` `jpg` `jpeg` `svg` | `preview_url` | `preview_url` | `ImagePreview`(`<img>`,`object-fit: contain`) |
|
|
197
|
+
| `binary` | `pdf` `docx` `xlsx` `xlsm` `xls` `pptx` `csv` `tsv`,以及**所有未登记的扩展名** | `preview_url` | `preview_url` | `UrlIframePreview`(`<iframe src>`,一般为后台转好的 PDF) |
|
|
198
|
+
|
|
199
|
+
关于类型解析:
|
|
200
|
+
|
|
201
|
+
- `AIFileInfo.type` 为**扩展名字符串**(如 `'pdf'` / `'py'`)或无扩展名的文件名(如 `'Dockerfile'`),大小写不敏感
|
|
202
|
+
- `type` 缺省时回退 `name` 推断;`报告.final.xlsx` 取 `xlsx`,`.gitignore` 取 `gitignore`
|
|
203
|
+
- `md` 为后台扩展名别名,与 `markdown` 等价,共用 Markdown 直渲染
|
|
204
|
+
- 未登记的扩展名一律落入 `binary` 走后台预览,前端不会因为新类型报错
|
|
205
|
+
|
|
206
|
+
`CodePreview` 的语言由扩展名映射到 highlight.js(`vue → xml`、`tsx → typescript`、`env / cfg / conf → ini` 等,其余交给 hljs 自身别名表,识别不了则按 `plaintext` 转义输出)。单文件超过 300KB 时跳过高亮直接转义,避免同步解析阻塞主线程。
|
|
207
|
+
|
|
208
|
+
### 加载态
|
|
209
|
+
|
|
210
|
+
| status | 表现 |
|
|
211
|
+
| ------ | ---- |
|
|
212
|
+
| `loading` | 预览区 [MessageLoading](/components/helper/message-loading) |
|
|
213
|
+
| `ready` | 对应 renderer 渲染 |
|
|
214
|
+
| `empty` | 「暂无可预览的文件」(无文件 / 未传 `onArtifactClick` / 缺所需 URL) |
|
|
215
|
+
| `error` | 「预览加载失败」+ 重试按钮 |
|
|
216
|
+
|
|
217
|
+
### 重载与取链约定
|
|
218
|
+
|
|
219
|
+
- **重载键**:`ArtifactPreviewHost` 以 `` `${outputId}:${type}` `` 监听文件变化;`outputId` 或 `type` 任一变化会重新 `load()`,仅改文件名等其它字段不会
|
|
220
|
+
- **取链**:`resolveArtifactUrls(file)` 每次重新调用 `onArtifactClick`;同文件进行中的请求会复用(并发去重)
|
|
221
|
+
- **重试**:错误态点击重试再次走 `load()`,重新取链并加载
|
|
222
|
+
- **竞态**:切换文件时 `useArtifactPreviewLoader` 用 `loadSeq` + `AbortController` 中断上一次 `fetch`,避免过期结果覆盖最新内容
|
|
223
|
+
|
|
224
|
+
下载图标仍由面板用 bkui `Loading` spin 单独表达。
|
|
225
|
+
|
|
226
|
+
## 内部结构(不导出)
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
message-artifacts/
|
|
230
|
+
├── file-artifact-panel.vue # 列表 + 下载头 + 挂载 Host
|
|
231
|
+
└── artifact-preview/
|
|
232
|
+
├── artifact-preview-host.vue # 状态机 UI + 分派 renderer
|
|
233
|
+
├── preview-strategy.ts # getArtifactPreviewStrategy(分类 → 策略查表)
|
|
234
|
+
├── use-artifact-preview-loader.ts
|
|
235
|
+
└── renderers/
|
|
236
|
+
├── code-preview.vue
|
|
237
|
+
├── html-preview.vue
|
|
238
|
+
├── image-preview.vue
|
|
239
|
+
├── markdown-preview.vue
|
|
240
|
+
├── txt-preview.vue
|
|
241
|
+
└── url-iframe-preview.vue
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
分类表与扩展名归一化在 `src/utils/file-type.ts`(导出 `AIFileKind` / `resolveFileKind` / `normalizeFileExtension`),与[文件图标](/components/helper/file-icon)共用同一份解析入口。
|
|
245
|
+
|
|
246
|
+
## API
|
|
247
|
+
|
|
248
|
+
### Props
|
|
249
|
+
|
|
250
|
+
| 属性名 | 类型 | 必填 | 说明 |
|
|
251
|
+
| --------- | ------------------- | ---- | -------------------------------------- |
|
|
252
|
+
| activeId | `string` | ✓ | 当前命中的文件 `outputId` |
|
|
253
|
+
| artifacts | `SessionArtifact[]` | ✓ | 当前会话全部文件产物(已按 `outputId` 去重) |
|
|
254
|
+
|
|
255
|
+
### Events
|
|
256
|
+
|
|
257
|
+
| 事件名 | 参数 | 说明 |
|
|
258
|
+
| ------ | ----------------- | -------------------------- |
|
|
259
|
+
| select | `(id: string)` | 列表内切换选中文件,参数为文件 `outputId` |
|
|
260
|
+
|
|
261
|
+
### Slots / Expose
|
|
262
|
+
|
|
263
|
+
无。
|
|
264
|
+
|
|
265
|
+
## 类型定义
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import type { AIFileInfo, SessionArtifact } from '@blueking/chat-x';
|
|
269
|
+
|
|
270
|
+
// 会话级文件产物:拍平去重后即为 AIFileInfo
|
|
271
|
+
type SessionArtifact = AIFileInfo;
|
|
272
|
+
|
|
273
|
+
type AIFileInfo = {
|
|
274
|
+
name: string;
|
|
275
|
+
outputId: string;
|
|
276
|
+
size: number;
|
|
277
|
+
/** 扩展名(如 'pdf' / 'py')或无扩展名文件名(如 'Dockerfile'),大小写不敏感 */
|
|
278
|
+
type: string;
|
|
279
|
+
};
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
> **破坏性变更**:原 `AIFileType` 枚举已移除,`AIFileInfo.type` 改为 `string`。此前写 `type: AIFileType.Pdf` 的代码改为 `type: 'pdf'` 即可;枚举成员的值与新字符串一一对应,运行时数据无需迁移。
|
|
283
|
+
|
|
284
|
+
## 关联 Composable
|
|
285
|
+
|
|
286
|
+
预览**命中与取链**由 [useArtifactPreview](/composables/use-artifact-preview) 提供(Provider / Consumer + `ARTIFACT_PREVIEW_TOKEN`)。**正文加载与渲染**由内部 `useArtifactPreviewLoader` + `ArtifactPreviewHost` 完成,不在该 composable 内。
|
|
287
|
+
|
|
288
|
+
## 关联组件
|
|
289
|
+
|
|
290
|
+
- [AssistantMessage](/components/message/assistant-message) — 文件产物来源(`property.artifacts`)
|
|
291
|
+
- [ChatContainer](/components/setup/chat-container) — 侧栏「文件产物」Tab 挂载场景,提供 `onArtifactClick`
|
|
292
|
+
- [MessageLoading](/components/helper/message-loading) — Host 预览区异步加载态
|
|
293
|
+
- [ExecutionSummary](/components/agent/execution-summary) — 同为侧栏 Tab 面板
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
按扩展名渲染文件类型图标:内联 svg,尺寸用 1em 跟随外层 font-size; 扩展名解析走 normalizeFileExtension(优先 fileType,缺省回退 fileName,大小写不敏感, 支持 Dockerfile / .gitignore 这类无扩展名或点号开头的文件);未登记类型返回 unknown 兜底图标。 源码位置:src/components/file-icon/file-icon.vue,图标注册表在 src/icons/file-icons.ts。
|
|
5
|
+
|
|
6
|
+
### 关联组件
|
|
7
|
+
- **file-artifact-panel** — 文件产物列表与预览头使用该组件展示类型图标
|
|
8
|
+
- **assistant-message** — 消息内的文件产物卡片使用该组件
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
<!-- FULL DOC -->
|
|
12
|
+
|
|
13
|
+
# FileIcon 文件类型图标
|
|
14
|
+
|
|
15
|
+
> **能力域**:辅助能力
|
|
16
|
+
|
|
17
|
+
`FileIcon` 按文件扩展名渲染对应的类型图标,用于文件列表、附件卡片、产物预览头等需要「一眼看出这是什么文件」的场景。图标以内联 svg 形式打进包内,不产生额外网络请求,也不需要消费方配置静态资源路径。
|
|
18
|
+
|
|
19
|
+
## 源码事实
|
|
20
|
+
|
|
21
|
+
- **源码位置**:`src/components/file-icon/file-icon.vue`
|
|
22
|
+
- **图标注册表**:`src/icons/file-icons.ts`(导出 `getFileIconSvg` / `UNKNOWN_FILE_ICON_SVG`)
|
|
23
|
+
- **扩展名解析**:`src/utils/file-type.ts` 的 `normalizeFileExtension`
|
|
24
|
+
|
|
25
|
+
## 核心能力
|
|
26
|
+
|
|
27
|
+
- **扩展名驱动**:优先取 `fileType`,缺省时回退 `fileName` 推断;大小写不敏感
|
|
28
|
+
- **特殊文件名**:`Dockerfile` / `Makefile` 这类无扩展名文件,以及 `.gitignore` / `.editorconfig` 这类点号开头的文件都能正确命中
|
|
29
|
+
- **多扩展名共用图标**:如 `xlsx` / `xls` / `csv` / `tsv` 共用表格图标,`tsx` / `jsx` 共用 React 图标
|
|
30
|
+
- **兜底不报错**:未登记的扩展名返回 `unknown` 图标,后台新增文件类型时前端不会缺图
|
|
31
|
+
- **尺寸自适应**:内部 svg 固定为 `1em`,直接用外层 `font-size` 控制大小
|
|
32
|
+
|
|
33
|
+
## 基础用法
|
|
34
|
+
|
|
35
|
+
```vue
|
|
36
|
+
<template>
|
|
37
|
+
<FileIcon file-type="pdf" />
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script setup lang="ts">
|
|
41
|
+
import { FileIcon } from '@blueking/chat-x';
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**渲染效果**
|
|
46
|
+
|
|
47
|
+
## 从文件名推断
|
|
48
|
+
|
|
49
|
+
后台未下发 `type` 时传 `fileName` 即可,组件会取最后一段扩展名:
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<template>
|
|
53
|
+
<!-- 取 xlsx -->
|
|
54
|
+
<FileIcon file-name="季度报告.final.xlsx" />
|
|
55
|
+
<!-- 取 gitignore -->
|
|
56
|
+
<FileIcon file-name=".gitignore" />
|
|
57
|
+
</template>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
两者同时传入时以 `fileType` 优先。
|
|
61
|
+
|
|
62
|
+
## 控制尺寸
|
|
63
|
+
|
|
64
|
+
图标宽高为 `1em`,用外层 `font-size` 控制即可,无需改 svg:
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<template>
|
|
68
|
+
<span style="font-size: 16px"><FileIcon file-type="py" /></span>
|
|
69
|
+
<span style="font-size: 32px"><FileIcon file-type="py" /></span>
|
|
70
|
+
</template>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API
|
|
74
|
+
|
|
75
|
+
### Props
|
|
76
|
+
|
|
77
|
+
| 属性名 | 类型 | 必填 | 默认值 | 说明 |
|
|
78
|
+
| -------- | -------- | ---- | ----------- | -------------------------------------------------------- |
|
|
79
|
+
| fileType | `string` | 否 | `undefined` | 文件类型:扩展名(如 `pdf` / `py`)或无扩展名文件名(如 `Dockerfile`) |
|
|
80
|
+
| fileName | `string` | 否 | `undefined` | 文件名,`fileType` 缺省时用于推断扩展名 |
|
|
81
|
+
|
|
82
|
+
两者都不传时渲染兜底图标。
|
|
83
|
+
|
|
84
|
+
### Emits / Slots / Expose
|
|
85
|
+
|
|
86
|
+
- 无。
|
|
87
|
+
|
|
88
|
+
## 图标覆盖范围
|
|
89
|
+
|
|
90
|
+
| 图标 | 覆盖扩展名 |
|
|
91
|
+
| ---- | ---------- |
|
|
92
|
+
| 文档类 | `pptx` / `docx` / `pdf` / `txt` / `rst` / `md` / `markdown` / `tex` |
|
|
93
|
+
| 表格类 | `xlsx` / `xlsm` / `xls` / `csv` / `tsv` |
|
|
94
|
+
| 前端 | `html` / `htm` / `css` / `scss` / `less` / `js` / `mjs` / `cjs` / `ts` / `tsx` / `jsx` / `vue` / `xml` |
|
|
95
|
+
| 后端 / 系统 | `py` / `go` / `rs` / `rb` / `java` / `kt` / `swift` / `c` / `h` / `cpp` / `hpp` / `cs` / `php` / `lua` / `r` / `scala` / `dart` / `sql` / `sh` / `bash` / `zsh` / `ps1` |
|
|
96
|
+
| 配置 | `json` / `jsonc` / `yaml` / `yml` / `toml` / `ini` / `cfg` / `conf` / `env` / `editorconfig` / `Makefile` |
|
|
97
|
+
| 工具链 | `Dockerfile` / `dockerignore` / `gitignore` |
|
|
98
|
+
| 图片 | `png` / `jpg` / `jpeg` / `svg` |
|
|
99
|
+
| 兜底 | 以上之外的所有类型 |
|
|
100
|
+
|
|
101
|
+
新增类型时在 `src/icons/file-icons.ts` 的 `FILE_ICON_GROUPS` 里补一行即可;对应 svg 需先放进 `src/svgs/` 并按需 `?raw` 引入(只引实际用到的,避免把整个图标库打进产物)。
|
|
102
|
+
|
|
103
|
+
## 使用建议
|
|
104
|
+
|
|
105
|
+
- 图标颜色由 svg 自带,不继承 `currentColor`,不要试图用 `color` 覆盖
|
|
106
|
+
- 需要与文件名同行展示时,给父容器设 `display: flex` + `gap`,组件本身已是 `inline-flex` 且 `flex-shrink: 0`
|
|
107
|
+
|
|
108
|
+
## 关联组件
|
|
109
|
+
|
|
110
|
+
- [FileArtifactPanel](../message/file-artifact-panel.md) — 文件产物列表与预览头使用该组件。
|
|
111
|
+
- [AssistantMessage](../message/assistant-message.md) — 消息内文件产物卡片的图标来源。
|
|
@@ -11,37 +11,45 @@
|
|
|
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
|
|
|
24
25
|
## 视觉原理
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
根节点 `.ai-info-message` 为横向 flex:两侧通过 `::before` / `::after` 拉伸出虚线(主题边框色),中间 `.ai-info-message-body` 承载文案(主题次要文案色)。整块正常占位,避免旧实现 `height: 0` 导致内容被裁切遮挡:
|
|
27
28
|
|
|
28
29
|
```
|
|
29
|
-
|
|
30
|
+
─────── 以下是新的对话 ───────
|
|
30
31
|
```
|
|
31
32
|
|
|
33
|
+
多行时,多条 `.ai-info-message-content` 在 body 内纵向排列(`gap: 4px`),两侧虚线仍夹住整块文案区域。
|
|
32
34
|
## 基础用法
|
|
33
35
|
|
|
34
36
|
`content` 传入字符串,渲染单行分隔信息:
|
|
35
37
|
|
|
36
38
|
```vue
|
|
37
39
|
<template>
|
|
38
|
-
<
|
|
40
|
+
<MessageRender :message="message" />
|
|
39
41
|
</template>
|
|
40
42
|
|
|
41
43
|
<script setup lang="ts">
|
|
42
|
-
import {
|
|
43
|
-
|
|
44
|
-
const
|
|
44
|
+
import { MessageRender, MessageRole, MessageStatus } from '@blueking/chat-x';
|
|
45
|
+
|
|
46
|
+
const message = {
|
|
47
|
+
id: '1',
|
|
48
|
+
messageId: '1',
|
|
49
|
+
role: MessageRole.Info,
|
|
50
|
+
content: '以下是新的对话',
|
|
51
|
+
status: MessageStatus.Complete,
|
|
52
|
+
};
|
|
45
53
|
</script>
|
|
46
54
|
```
|
|
47
55
|
|
|
@@ -49,15 +57,24 @@
|
|
|
49
57
|
|
|
50
58
|
## 多行信息
|
|
51
59
|
|
|
52
|
-
`content`
|
|
60
|
+
`content` 传入字符串数组时,每个元素渲染为一行居中文案,在中间 body 内纵向排列,两侧虚线夹住整块区域:
|
|
53
61
|
|
|
54
62
|
```vue
|
|
55
63
|
<template>
|
|
56
|
-
<
|
|
64
|
+
<MessageRender :message="message" />
|
|
57
65
|
</template>
|
|
58
66
|
|
|
59
67
|
<script setup lang="ts">
|
|
60
|
-
import {
|
|
68
|
+
import { MessageRender, MessageRole, MessageStatus } from '@blueking/chat-x';
|
|
69
|
+
|
|
70
|
+
// 运行时 content 兼容 string[](TS 类型声明多为 string)
|
|
71
|
+
const message = {
|
|
72
|
+
id: '1',
|
|
73
|
+
messageId: '1',
|
|
74
|
+
role: MessageRole.Info,
|
|
75
|
+
content: ['会话已重置', '以下是新的对话'],
|
|
76
|
+
status: MessageStatus.Complete,
|
|
77
|
+
};
|
|
61
78
|
</script>
|
|
62
79
|
```
|
|
63
80
|
|
|
@@ -118,7 +135,7 @@
|
|
|
118
135
|
|
|
119
136
|
| 属性名 | 类型 | 说明 |
|
|
120
137
|
| --------- | -------------------- | ------------------------------------------------------------------ |
|
|
121
|
-
| content | `string \| string[]` |
|
|
138
|
+
| content | `string \| string[]` | 信息内容。字符串渲染单行;数组在中间区域纵向多行展示,两侧虚线夹住整块 |
|
|
122
139
|
| id | `number \| string` | 消息 ID(接收但不使用,由 MessageContainer 管理) |
|
|
123
140
|
| messageId | `number \| string` | 消息唯一标识(接收但不使用) |
|
|
124
141
|
| status | `MessageStatus` | 消息状态(接收但不使用,组件无状态相关渲染逻辑) |
|
|
@@ -138,6 +138,7 @@ type UserQuestionOptionItem = {
|
|
|
138
138
|
- 前端会为每道**选择题**追加 `label: 'others'` 的自由输入项;后端无需重复下发该选项。
|
|
139
139
|
- 当用户选择 Others 时,`answer[].description` 为用户输入文本。
|
|
140
140
|
- 业务可通过 `UserQuestionCard` 的 `#question` slot 渲染自定义表单;作答有效时调用 `setAnswer` 回传 `UserQuestionAnswerItem`,无效时传 `undefined`。
|
|
141
|
+
- UI 一次只展示一题:标题栏 `< 当前题 / 总题数 >` 切换;单选预设选项作答后自动跳下一题,多选 / Others 需手动切换(协议字段不变)。
|
|
141
142
|
|
|
142
143
|
## Interrupt
|
|
143
144
|
|