@blueking/chat-x 0.0.48-beta.1 → 0.0.49-beta.2
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 +23 -0
- package/dist/ag-ui/types/index.d.ts +1 -0
- package/dist/ag-ui/types/messages.d.ts +2 -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 +7 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/preview-strategy.d.ts +9 -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/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 +23 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue.d.ts +12 -0
- package/dist/components/chat-message/assistant-message/message-artifacts/file-icon.d.ts +29 -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 +14 -2
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/use-artifact-preview.d.ts +56 -0
- package/dist/composables/use-custom-tab.d.ts +2 -0
- package/dist/composables/use-message-group.d.ts +433 -0
- package/dist/icons/file.d.ts +24 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/index.css +1 -1
- package/dist/index.js +2217 -1689
- package/dist/index.js.map +1 -1
- package/dist/lang/lang.d.ts +8 -1
- package/dist/mcp/generated/docs/activity-message.md +122 -97
- package/dist/mcp/generated/docs/assistant-message.md +125 -62
- package/dist/mcp/generated/docs/chat-container.md +97 -18
- 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/file-artifact-panel.md +275 -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 +4 -21
- package/dist/mcp/generated/docs/message-render.md +47 -59
- package/dist/mcp/generated/docs/messages.md +5 -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 +8 -8
- package/dist/mcp/generated/docs/use-artifact-preview.md +232 -0
- package/dist/mcp/generated/docs/use-custom-tab.md +18 -5
- package/dist/mcp/generated/docs/use-message-group.md +29 -0
- package/dist/mcp/generated/docs/user-message.md +185 -121
- package/dist/mcp/generated/docs/user-question-card.md +6 -3
- package/dist/mcp/generated/index.json +83 -13
- package/dist/mcp/index.js +0 -0
- package/package.json +20 -21
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
useArtifactPreviewProvider 维护 activeArtifactId(值为 outputId),openPreview 命中文件并触发 onOpen 打开侧栏 Tab; 并通过 getOnArtifactClick 封装 resolveArtifactUrls(TTL 8 分钟缓存;常规只传 file,force 可强制刷新,并发去重); useArtifactPreviewConsumer 在后代注入同一套 API。SessionArtifact 即 AIFileInfo,会话内以 outputId 为唯一键。 正文加载与分类型渲染不在本 composable,由 FileArtifactPanel 内 ArtifactPreviewHost 完成(重载键 outputId:type)。 FILE_ARTIFACT_TAB_NAME 标识固定「文件产物」Tab。
|
|
5
|
+
|
|
6
|
+
### 关联组件
|
|
7
|
+
- **chat-container** — Provider 主场景,聚合 sessionArtifacts 并挂载 FileArtifactPanel
|
|
8
|
+
- **file-artifact-panel** — 侧栏面板消费 activeArtifactId 与 setActiveArtifactId;预览加载在面板内 Host
|
|
9
|
+
- **assistant-message** — 文件产物来源 property.artifacts
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
<!-- FULL DOC -->
|
|
13
|
+
|
|
14
|
+
# useArtifactPreview 文件产物预览
|
|
15
|
+
|
|
16
|
+
> **分类**:composable
|
|
17
|
+
|
|
18
|
+
Provider/Consumer 模式的文件产物预览状态管理。Provider 在 `ChatContainer` 中创建,负责维护当前命中的文件 `outputId`;Consumer 在深层 `ArtifactFileCard` 中注入,用于点击卡片触发预览。
|
|
19
|
+
|
|
20
|
+
**职责边界**:
|
|
21
|
+
|
|
22
|
+
- **本 composable**:维护「命中文件」与「URL 解析」(TTL 缓存 + 并发去重;常规 `resolveArtifactUrls(file)`,重试可 `force` 刷新);打开侧栏 Tab(`addCustomTab`)由容器通过 `onOpen` 注入
|
|
23
|
+
- **不在本 composable**:聚合会话文件列表、渲染预览面板、按类型 fetch 正文 / iframe 展示 —— 分别由 `useMessageGroup.sessionArtifacts`、`FileArtifactPanel`、内部 `ArtifactPreviewHost` + `useArtifactPreviewLoader` 承担(预览重载键为 `outputId:type`)
|
|
24
|
+
|
|
25
|
+
## 函数签名
|
|
26
|
+
|
|
27
|
+
### useArtifactPreviewProvider
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
function useArtifactPreviewProvider(options: {
|
|
31
|
+
/** 读取业务侧异步取链回调(getter 保持对 props 变更敏感) */
|
|
32
|
+
getOnArtifactClick?: () => OnArtifactClick | undefined;
|
|
33
|
+
/** 命中文件后触发:由容器负责 addCustomTab + 展开侧栏 + 选中 Tab */
|
|
34
|
+
onOpen: (outputId: string) => void;
|
|
35
|
+
}): {
|
|
36
|
+
activeArtifactId: ShallowRef<string>;
|
|
37
|
+
canResolveArtifactUrl: ComputedRef<boolean>;
|
|
38
|
+
openPreview: (payload: OpenArtifactPreviewPayload) => void;
|
|
39
|
+
resolveArtifactUrls: (file: AIFileInfo, options?: { force?: boolean }) => Promise<ArtifactUrlResult>;
|
|
40
|
+
setActiveArtifactId: (id: string) => void;
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### useArtifactPreviewConsumer
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
function useArtifactPreviewConsumer():
|
|
48
|
+
| undefined
|
|
49
|
+
| {
|
|
50
|
+
activeArtifactId: Ref<string>;
|
|
51
|
+
canResolveArtifactUrl: ComputedRef<boolean>;
|
|
52
|
+
openPreview: (payload: OpenArtifactPreviewPayload) => void;
|
|
53
|
+
resolveArtifactUrls: (file: AIFileInfo, options?: { force?: boolean }) => Promise<ArtifactUrlResult>;
|
|
54
|
+
setActiveArtifactId: (id: string) => void;
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 使用示例
|
|
59
|
+
|
|
60
|
+
### Provider(ChatContainer)
|
|
61
|
+
|
|
62
|
+
会话级文件产物由 [`useMessageGroup`](./use-message-group) 统一聚合(`sessionArtifacts`),Provider 只负责命中与打开侧栏 Tab:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import {
|
|
66
|
+
useArtifactPreviewProvider,
|
|
67
|
+
useCustomTabProvider,
|
|
68
|
+
useMessageGroup,
|
|
69
|
+
FILE_ARTIFACT_TAB_NAME,
|
|
70
|
+
} from '@blueking/chat-x';
|
|
71
|
+
import { t } from '@blueking/chat-x/lang';
|
|
72
|
+
|
|
73
|
+
const { addCustomTab, ensureCustomTab, removeCustomTab } = useCustomTabProvider({ /* ... */ });
|
|
74
|
+
|
|
75
|
+
// 会话级文件产物聚合已内聚在 useMessageGroup,直接消费
|
|
76
|
+
const { sessionArtifacts } = useMessageGroup({ keyword, messages, selectedUserMessages });
|
|
77
|
+
|
|
78
|
+
const { activeArtifactId, setActiveArtifactId } = useArtifactPreviewProvider({
|
|
79
|
+
getOnArtifactClick: () => props.onArtifactClick,
|
|
80
|
+
// 点击文件卡片:展开侧栏并选中「文件产物」Tab
|
|
81
|
+
onOpen: () => {
|
|
82
|
+
addCustomTab({
|
|
83
|
+
closable: false,
|
|
84
|
+
label: t('文件产物'),
|
|
85
|
+
name: FILE_ARTIFACT_TAB_NAME,
|
|
86
|
+
order: -1,
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// 有产物时静默挂上 Tab(不抢焦点);无产物时清理
|
|
92
|
+
watch(sessionArtifacts, list => {
|
|
93
|
+
if (!list.length) {
|
|
94
|
+
removeCustomTab(FILE_ARTIFACT_TAB_NAME);
|
|
95
|
+
setActiveArtifactId('');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
ensureCustomTab({
|
|
99
|
+
closable: false,
|
|
100
|
+
label: t('文件产物'),
|
|
101
|
+
name: FILE_ARTIFACT_TAB_NAME,
|
|
102
|
+
order: -1,
|
|
103
|
+
});
|
|
104
|
+
if (!list.some(item => item.outputId === activeArtifactId.value)) {
|
|
105
|
+
setActiveArtifactId(list[0].outputId);
|
|
106
|
+
}
|
|
107
|
+
}, { immediate: true });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Consumer(ArtifactFileCard)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { useArtifactPreviewConsumer } from '@blueking/chat-x';
|
|
114
|
+
|
|
115
|
+
const artifactPreview = useArtifactPreviewConsumer();
|
|
116
|
+
|
|
117
|
+
// 有 Provider 时卡片可点击;无 Provider 时返回 undefined,卡片不可点击
|
|
118
|
+
const clickable = computed(() => !!props.onPreview || !!artifactPreview);
|
|
119
|
+
|
|
120
|
+
const handleCardClick = () => {
|
|
121
|
+
if (props.onPreview) {
|
|
122
|
+
props.onPreview(props.file);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
artifactPreview?.openPreview({ file: props.file });
|
|
126
|
+
};
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 侧栏列表内切换命中文件
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// FileArtifactPanel 列表点击 → emit select(outputId) → 容器调用 setActiveArtifactId
|
|
133
|
+
// 右侧预览由面板内 ArtifactPreviewHost 消费 activeArtifact,自行取链并按类型渲染
|
|
134
|
+
<FileArtifactPanel
|
|
135
|
+
:active-id="activeArtifactId"
|
|
136
|
+
:artifacts="sessionArtifacts"
|
|
137
|
+
@select="setActiveArtifactId"
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 业务侧取链(ChatContainer `onArtifactClick`)
|
|
142
|
+
|
|
143
|
+
文本类预览需要可 `fetch` 的 `download_url`;iframe 类需要 `preview_url`(一般为后台转好的 PDF):
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const onArtifactClick = async (file: AIFileInfo) => {
|
|
147
|
+
const res = await api.getArtifactUrls(file.outputId);
|
|
148
|
+
return {
|
|
149
|
+
download_url: res.download_url,
|
|
150
|
+
preview_url: res.preview_url,
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 内置常量
|
|
156
|
+
|
|
157
|
+
| 常量名 | 值 | 说明 |
|
|
158
|
+
| ------------------------- | ------------------ | ----------------------------------------- |
|
|
159
|
+
| `FILE_ARTIFACT_TAB_NAME` | `'file-artifact'` | 「文件产物」侧栏 Tab 的固定标识,不可关闭 |
|
|
160
|
+
| `ARTIFACT_PREVIEW_TOKEN` | `Symbol` | provide/inject 注入 Token |
|
|
161
|
+
|
|
162
|
+
## 返回值说明
|
|
163
|
+
|
|
164
|
+
| 属性/方法名 | 类型 | 说明 |
|
|
165
|
+
| ------------------- | ----------------------------------------- | -------------------------------------------------------------------- |
|
|
166
|
+
| activeArtifactId | `ShallowRef<string>` | 当前命中的文件 `outputId` |
|
|
167
|
+
| canResolveArtifactUrl | `ComputedRef<boolean>` | 是否具备异步取链能力(有 `onArtifactClick` 时为 true,下载按钮据此显隐) |
|
|
168
|
+
| openPreview | `(payload: OpenArtifactPreviewPayload) => void` | 由文件卡片触发:以 `file.outputId` 更新命中态、调用 `onOpen` |
|
|
169
|
+
| resolveArtifactUrls | `(file: AIFileInfo, options?: { force?: boolean }) => Promise<ArtifactUrlResult>` | 调用 `onArtifactClick` 取链;成功结果按 `outputId` 缓存 8 分钟;**常规调用只传 `file`**,仅预览重试 / 强刷传 `{ force: true }`(不要传 `undefined` 作为第二参);并发去重 |
|
|
170
|
+
| setActiveArtifactId | `(id: string) => void` | 直接设置命中文件 `outputId`;侧栏列表内切换选中时使用 |
|
|
171
|
+
|
|
172
|
+
## 类型定义
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import type { AIFileInfo, ArtifactUrlResult, OnArtifactClick } from '@blueking/chat-x';
|
|
176
|
+
|
|
177
|
+
/** 打开预览时的入参 */
|
|
178
|
+
type OpenArtifactPreviewPayload = {
|
|
179
|
+
file: AIFileInfo;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 会话级文件产物:以 outputId 为会话内唯一键(同 outputId 视为同一文件)。
|
|
184
|
+
* 拍平去重后即为 AIFileInfo,此处用别名标明语义。
|
|
185
|
+
*/
|
|
186
|
+
type SessionArtifact = AIFileInfo;
|
|
187
|
+
|
|
188
|
+
/** onArtifactClick 返回值(snake_case) */
|
|
189
|
+
type ArtifactUrlResult = {
|
|
190
|
+
download_url?: string;
|
|
191
|
+
preview_url?: string;
|
|
192
|
+
};
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## 唯一键规则
|
|
196
|
+
|
|
197
|
+
会话内以 **`outputId`** 作为文件产物唯一键:
|
|
198
|
+
|
|
199
|
+
- 同一 `outputId` 在多条 `AssistantMessage` 中出现时,`sessionArtifacts` 去重并保留**最后一次**出现的文件信息
|
|
200
|
+
- `activeArtifactId`、列表 `:key`、`select` 事件参数均使用 `outputId`
|
|
201
|
+
- 文件名可能重复,**不可**作为唯一键
|
|
202
|
+
|
|
203
|
+
## 完整触发链路
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
ArtifactFileCard(点击)
|
|
207
|
+
└─ useArtifactPreviewConsumer().openPreview({ file })
|
|
208
|
+
└─ useArtifactPreviewProvider(ChatContainer)
|
|
209
|
+
├─ activeArtifactId = file.outputId
|
|
210
|
+
└─ onOpen(outputId) → addCustomTab(FILE_ARTIFACT_TAB_NAME) 展开并选中
|
|
211
|
+
└─ FileArtifactPanel(列表 + 下载头,@select → setActiveArtifactId)
|
|
212
|
+
└─ ArtifactPreviewHost(loader + 分类型 renderer)
|
|
213
|
+
|
|
214
|
+
sessionArtifacts 变化(有产物)
|
|
215
|
+
└─ ensureCustomTab(FILE_ARTIFACT_TAB_NAME) 静默挂上,不抢当前选中(如执行情况)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
分类型预览策略见 [FileArtifactPanel 预览机制](../components/message/file-artifact-panel#预览机制)。
|
|
219
|
+
|
|
220
|
+
## 设计特点
|
|
221
|
+
|
|
222
|
+
- **职责单一**:composable 不直接调用 `useCustomTab`,侧栏 Tab 打开逻辑由 `onOpen` 注入;也不做正文 fetch / iframe 渲染
|
|
223
|
+
- **ShallowRef 优先**:`activeArtifactId` 使用 `shallowRef`,避免不必要的深层响应式开销
|
|
224
|
+
- **Consumer 兜底**:`useArtifactPreviewConsumer` 无 Provider 时返回 `undefined`,文件卡片在无容器上下文时自动不可点击
|
|
225
|
+
- **与 useCustomTab 协作**:点击卡片走 `addCustomTab`(展开 + 选中);会话已有产物时走 `ensureCustomTab`(只挂载,不抢焦点);无文件产物时由容器 `removeCustomTab` 清理
|
|
226
|
+
|
|
227
|
+
## 关联组件
|
|
228
|
+
|
|
229
|
+
- [ChatContainer](../components/setup/chat-container) — Provider 主场景,内置「文件产物」Tab
|
|
230
|
+
- [FileArtifactPanel](../components/message/file-artifact-panel) — 侧栏列表与预览 Host 挂载
|
|
231
|
+
- [AssistantMessage](../components/message/assistant-message) — 文件产物来源(`property.artifacts`)
|
|
232
|
+
- [useCustomTab](./use-custom-tab) — `addCustomTab` / `ensureCustomTab` 分工
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- AI SUMMARY -->
|
|
2
2
|
## 快速了解
|
|
3
3
|
|
|
4
|
-
useCustomTabProvider 返回 tabs、selectedTab、isCollapse 及 add/remove/selectCustomTab,并通过 provide 共享;可选 onTabChange 在切换时拉取数据。 useCustomTabConsumer 在后代注入同一套 API,常用于侧栏动态节点详情等。EXECUTION_TAB_NAME 标识默认「执行情况」Tab。 ChatContainer 侧栏集成 Provider 与 Tab UI。
|
|
4
|
+
useCustomTabProvider 返回 tabs、selectedTab、isCollapse 及 add/ensure/remove/selectCustomTab,并通过 provide 共享;可选 onTabChange 在切换时拉取数据。 ensureCustomTab 只挂载/合并元信息,不展开侧栏、不切换选中;addCustomTab 会展开并选中。 useCustomTabConsumer 在后代注入同一套 API,常用于侧栏动态节点详情等。EXECUTION_TAB_NAME 标识默认「执行情况」Tab。 ChatContainer 侧栏集成 Provider 与 Tab UI。
|
|
5
5
|
|
|
6
6
|
### 关联组件
|
|
7
7
|
- **chat-container** — Provider 与侧栏 Tab 主场景
|
|
@@ -30,6 +30,7 @@ function useCustomTabProvider<T extends Record<string, unknown>>(options: {
|
|
|
30
30
|
selectedTab: Ref<CustomTab<T>>;
|
|
31
31
|
isCollapse: ShallowRef<boolean>;
|
|
32
32
|
addCustomTab: (tab: CustomTab<T>) => void;
|
|
33
|
+
ensureCustomTab: (tab: CustomTab<T>) => void;
|
|
33
34
|
removeCustomTab: (tabName: string) => void;
|
|
34
35
|
selectCustomTab: (tab: CustomTab<T>) => void;
|
|
35
36
|
resetCustomTab: () => void;
|
|
@@ -46,6 +47,7 @@ function useCustomTabConsumer<T extends Record<string, unknown>>():
|
|
|
46
47
|
displayTabs: ComputedRef<CustomTab<T>[]>;
|
|
47
48
|
selectedTab: ShallowRef<CustomTab<T> | null>;
|
|
48
49
|
addCustomTab: (tab: CustomTab<T>) => void;
|
|
50
|
+
ensureCustomTab: (tab: CustomTab<T>) => void;
|
|
49
51
|
removeCustomTab: (tabName: string) => void;
|
|
50
52
|
selectCustomTab: (tab: CustomTab<T>) => void;
|
|
51
53
|
resetCustomTab: () => void;
|
|
@@ -59,7 +61,7 @@ function useCustomTabConsumer<T extends Record<string, unknown>>():
|
|
|
59
61
|
```typescript
|
|
60
62
|
import { useCustomTabProvider, EXECUTION_TAB_NAME } from '@blueking/chat-x';
|
|
61
63
|
|
|
62
|
-
const { tabs, selectedTab, isCollapse, addCustomTab, removeCustomTab, selectCustomTab, resetCustomTab } =
|
|
64
|
+
const { tabs, selectedTab, isCollapse, addCustomTab, ensureCustomTab, removeCustomTab, selectCustomTab, resetCustomTab } =
|
|
63
65
|
useCustomTabProvider({
|
|
64
66
|
onTabChange: async tab => {
|
|
65
67
|
// Tab 切换时加载数据
|
|
@@ -76,7 +78,7 @@ import { useCustomTabConsumer } from '@blueking/chat-x';
|
|
|
76
78
|
|
|
77
79
|
const tabManager = useCustomTabConsumer();
|
|
78
80
|
|
|
79
|
-
// 添加一个自定义 Tab
|
|
81
|
+
// 添加一个自定义 Tab(展开侧栏并选中)
|
|
80
82
|
tabManager?.addCustomTab({
|
|
81
83
|
name: 'node-detail-123',
|
|
82
84
|
label: '节点详情',
|
|
@@ -86,6 +88,14 @@ tabManager?.addCustomTab({
|
|
|
86
88
|
},
|
|
87
89
|
});
|
|
88
90
|
|
|
91
|
+
// 仅确保 Tab 存在(不展开、不切换选中)—— 如侧栏已因执行情况打开时同步挂上文件产物
|
|
92
|
+
tabManager?.ensureCustomTab({
|
|
93
|
+
name: 'file-artifact',
|
|
94
|
+
label: '文件产物',
|
|
95
|
+
closable: false,
|
|
96
|
+
order: -1,
|
|
97
|
+
});
|
|
98
|
+
|
|
89
99
|
// 移除 Tab
|
|
90
100
|
tabManager?.removeCustomTab('node-detail-123');
|
|
91
101
|
```
|
|
@@ -106,7 +116,8 @@ tabManager?.removeCustomTab('node-detail-123');
|
|
|
106
116
|
| displayTabs | `ComputedRef<CustomTab[]>` | Tab 栏实际展示列表:过滤 `visible === false`,按 `order` 升序稳定排序 |
|
|
107
117
|
| selectedTab | `Ref<CustomTab>` | 当前选中的 Tab;选中项被隐藏时自动回退到首个可见 Tab |
|
|
108
118
|
| isCollapse | `ShallowRef<boolean>` | 侧边栏折叠状态;`addCustomTab` 时自动设为 `false` |
|
|
109
|
-
| addCustomTab | `(tab: CustomTab) => void` |
|
|
119
|
+
| addCustomTab | `(tab: CustomTab) => void` | 添加/合并 Tab,**展开侧栏并选中**目标 Tab |
|
|
120
|
+
| ensureCustomTab | `(tab: CustomTab) => void` | 添加/合并 Tab,**不展开、不切换选中**;用于静默挂载(如文件产物) |
|
|
110
121
|
| removeCustomTab | `(tabName: string) => void` | 移除指定 Tab |
|
|
111
122
|
| selectCustomTab | `(tab: CustomTab) => void` | 切换到指定 Tab,触发 `onTabChange` 回调 |
|
|
112
123
|
| resetCustomTab | `() => void` | 重置为仅保留「执行情况」Tab、折叠侧栏并选中默认 Tab;`ChatContainer` 在卸载时调用,避免残留自定义 Tab |
|
|
@@ -136,7 +147,9 @@ interface CustomTab<T = Record<string, unknown>> {
|
|
|
136
147
|
- 排序为稳定排序,`order` 相同的 Tab 保持插入先后顺序
|
|
137
148
|
- 选中的 Tab 被配置隐藏时,内容不再渲染,自动切换到首个可见 Tab
|
|
138
149
|
- `addCustomTab` 同时展开侧边栏(`isCollapse = false`)并在 `nextTick` 后自动选中目标 Tab;同名 Tab 合并更新
|
|
150
|
+
- `ensureCustomTab` 与 `addCustomTab` 共用合并逻辑,但不改 `isCollapse`、不切换 `selectedTab`;适合「侧栏已打开时同步挂上文件产物」等场景
|
|
139
151
|
|
|
140
152
|
## 关联组件
|
|
141
153
|
|
|
142
|
-
- [ChatContainer](../components/setup/chat-container) — 侧栏 Tab 与自定义面板
|
|
154
|
+
- [ChatContainer](../components/setup/chat-container) — 侧栏 Tab 与自定义面板
|
|
155
|
+
- [useArtifactPreview](./use-artifact-preview) — 文件产物 Tab:有产物时 `ensureCustomTab`,点击卡片时 `addCustomTab`
|
|
@@ -28,6 +28,7 @@ function useMessageGroup(options: {
|
|
|
28
28
|
}): {
|
|
29
29
|
messageGroups: Ref<MessageGroup[]>;
|
|
30
30
|
executionGroups: ComputedRef<MessageGroup[]>;
|
|
31
|
+
sessionArtifacts: ComputedRef<SessionArtifact[]>;
|
|
31
32
|
pendingApprovalCount: ComputedRef<number>;
|
|
32
33
|
pendingApprovalTipText: ComputedRef<string>;
|
|
33
34
|
isShareMode: ShallowRef<boolean>;
|
|
@@ -116,6 +117,33 @@ const isExecutionMessage = (m: Message): boolean => {
|
|
|
116
117
|
| toolCall | `function.name`、`mcpName`、`description`、`arguments`、`id` |
|
|
117
118
|
| flow_agent | 各任务 `task_name`、各节点 `name` |
|
|
118
119
|
|
|
120
|
+
## sessionArtifacts 会话级文件产物
|
|
121
|
+
|
|
122
|
+
`sessionArtifacts` 拍平当前会话所有 `AssistantMessage.property.artifacts`,供 `ChatContainer` 侧栏「文件产物」Tab 聚合预览。以 **`outputId`** 为会话内唯一键去重(同 `outputId` 视为同一文件),保留最后一次出现的文件信息,列表顺序与「最后一次出现」的相对顺序一致:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const sessionArtifacts = computed(() => {
|
|
126
|
+
// delete + set:同 key 覆盖内容,并把该项挪到 Map 末尾,保证「最后出现」顺序
|
|
127
|
+
const byOutputId = new Map();
|
|
128
|
+
for (const message of messages.value) {
|
|
129
|
+
if (message.role !== MessageRole.Assistant) continue;
|
|
130
|
+
const artifacts = message.property?.artifacts;
|
|
131
|
+
if (!artifacts?.length) continue;
|
|
132
|
+
for (const file of artifacts) {
|
|
133
|
+
if (byOutputId.has(file.outputId)) {
|
|
134
|
+
byOutputId.delete(file.outputId);
|
|
135
|
+
}
|
|
136
|
+
byOutputId.set(file.outputId, file);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return Array.from(byOutputId.values());
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> `SessionArtifact` 即为 `AIFileInfo` 别名;文件名可能重复,不可作唯一键。
|
|
144
|
+
|
|
145
|
+
预览命中与取链见 [useArtifactPreview](./use-artifact-preview);侧栏列表与分类型预览(`ArtifactPreviewHost`)见 [FileArtifactPanel](../components/message/file-artifact-panel)。
|
|
146
|
+
|
|
119
147
|
## 待审批统计
|
|
120
148
|
|
|
121
149
|
`useMessageGroup` 会统计消息列表中处于待审批状态的 AI Dev 审批中断:
|
|
@@ -186,6 +214,7 @@ const {
|
|
|
186
214
|
| ---------------- | ----------------------------- | --------------------------------------------------------------------------- |
|
|
187
215
|
| messageGroups | `Ref<MessageGroup[]>` | 完整消息分组列表 |
|
|
188
216
|
| executionGroups | `ComputedRef<MessageGroup[]>` | 仅包含执行类消息的分组(工具调用 + FlowAgent),自动提取 `userMessageTitle` |
|
|
217
|
+
| sessionArtifacts | `ComputedRef<SessionArtifact[]>` | 拍平会话所有 AssistantMessage 文件产物,按 `outputId` 去重(保留最后一次) |
|
|
189
218
|
| pendingApprovalCount | `ComputedRef<number>` | 当前消息中待审批 AI Dev 审批中断的数量 |
|
|
190
219
|
| pendingApprovalTipText | `ComputedRef<string>` | 待审批阻塞发送提示文案;无待审批时为空字符串 |
|
|
191
220
|
| isShareMode | `ShallowRef<boolean>` | 是否处于分享模式 |
|