@blueking/chat-x 0.0.49-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.
Files changed (35) hide show
  1. package/dist/ag-ui/types/constants.d.ts +1 -0
  2. package/dist/ag-ui/types/file.d.ts +1 -1
  3. package/dist/components/chat-message/assistant-message/assistant-message.vue.d.ts +12 -1
  4. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-file-card.vue.d.ts +0 -2
  5. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/artifact-preview-host.vue.d.ts +1 -2
  6. package/dist/components/chat-message/assistant-message/message-artifacts/artifact-preview/use-artifact-preview-loader.d.ts +4 -2
  7. package/dist/components/chat-message/assistant-message/message-artifacts/message-artifacts.vue.d.ts +0 -1
  8. package/dist/components/chat-message/interrupt-message/user-question/use-user-question.d.ts +7 -2
  9. package/dist/components/chat-message/user-message/user-message.vue.d.ts +14 -2
  10. package/dist/composables/use-artifact-preview.d.ts +17 -20
  11. package/dist/composables/use-custom-tab.d.ts +2 -0
  12. package/dist/composables/use-message-group.d.ts +1 -2
  13. package/dist/index.css +1 -1
  14. package/dist/index.js +514 -469
  15. package/dist/index.js.map +1 -1
  16. package/dist/lang/lang.d.ts +3 -1
  17. package/dist/mcp/generated/docs/assistant-message.md +1 -1
  18. package/dist/mcp/generated/docs/chat-container.md +7 -6
  19. package/dist/mcp/generated/docs/chat-input.md +2 -10
  20. package/dist/mcp/generated/docs/constants.md +3 -1
  21. package/dist/mcp/generated/docs/content-render.md +2 -10
  22. package/dist/mcp/generated/docs/file-artifact-panel.md +32 -36
  23. package/dist/mcp/generated/docs/info-message.md +6 -5
  24. package/dist/mcp/generated/docs/interrupt.md +1 -0
  25. package/dist/mcp/generated/docs/message-container.md +4 -21
  26. package/dist/mcp/generated/docs/message-render.md +4 -27
  27. package/dist/mcp/generated/docs/messages.md +5 -0
  28. package/dist/mcp/generated/docs/reasoning-message.md +2 -9
  29. package/dist/mcp/generated/docs/toolcall-render.md +8 -8
  30. package/dist/mcp/generated/docs/use-artifact-preview.md +45 -50
  31. package/dist/mcp/generated/docs/use-custom-tab.md +18 -5
  32. package/dist/mcp/generated/docs/use-message-group.md +13 -8
  33. package/dist/mcp/generated/docs/user-question-card.md +6 -3
  34. package/dist/mcp/generated/index.json +7 -7
  35. package/package.json +2 -2
@@ -145,6 +145,8 @@ export declare const lang: {
145
145
  readonly 单选: "Single";
146
146
  readonly 多选: "Multiple";
147
147
  readonly 其他: "Others";
148
+ readonly 已完成: "Completed";
149
+ readonly 题: "question(s)";
148
150
  readonly 回答内容: "Answers";
149
151
  readonly 已回复: "Replied";
150
152
  readonly '\u8BF7\u8F93\u5165...': "Please enter...";
@@ -154,4 +156,4 @@ export declare const lang: {
154
156
  readonly 预览加载失败: "Failed to load preview";
155
157
  readonly 暂无可预览的文件: "No file to preview";
156
158
  };
157
- export declare const t: (key: keyof typeof lang) => "Send" | "Stop" | "Ask AI" | "Copy" | "Share" | "Like" | "Unsatisfied" | "Delete" | "Quote" | "Regenerate" | "Regenerating will clear the content below" | "Submit" | "Cancel" | "Preview Content" | "Jump to Detail" | "Call Tool:" | "Calling..." | "Call Success" | "Call Failed" | "Tell us your thoughts" | "What makes you satisfied?" | "What makes you dissatisfied?" | "Return Content" | "Edit" | "Deep Thinking" | "Quick Thinking" | "Image to Text" | "Loading image..." | "Failed to load image" | "Thinking..." | "Thinking Completed" | "Thinking Failed" | "Copy Success" | "Copy Failed" | "Return to bottom" | "Stop generating" | "Stopping" | "Duration" | "Parameters" | "Description" | "Execution Status" | "Running" | "Success" | "Failed" | "Pending" | "To Be Executed" | "Details" | "Retry" | "Retrying" | "Skipping" | "The task is retrying and cannot be skipped" | "The task is skipping and cannot be retried" | "Node" | "Node Config" | "Node Output" | "Basic Info" | "Flow Template" | "Node Name" | "Step Name" | "Execution Plan" | "Optional" | "Failure Handler" | "Timeout Control" | "Yes" | "No" | "Input Params" | "Output Params" | "Param Name" | "Param Value" | "Name" | "Structured Output" | "Manual Skip" | "No Data" | "Call MCP:" | "More" | "Algorithm Plan Review Ticket" | "Reviewing" | "Approving" | "Abandoned" | "Approved" | "Cancelled" | "Expired" | "Rejected" | "Revoked" | "Ticket No." | "Submitted At" | "Current Handler" | "None" | "View Ticket Detail" | "Copy Ticket" | "Copy Ticket Link" | "Cancel Approval" | "Approval Cancelled" | "Refresh Ticket Status" | "This ticket has been rejected and cannot be cancelled" | "This ticket has been approved and cannot be cancelled" | "This ticket has been cancelled, no need to click again" | "Approval cannot be cancelled in the current status" | "There are {count} pending approval tickets in the current conversation. To continue, cancel approval first." | "Unsupported interrupt message" | "Searching" | "Search Completed" | "Upload File" | "Select model" | "Search models" | "Requesting..." | "Cancel satisfied" | "Cancel dissatisfied" | "Confirm delete this answer?" | "This operation cannot be undone. Please proceed with caution!" | "Preview" | "Zoom Out" | "Zoom In" | "Rotate" | "Download" | "Sorry, image loading failed. Please try reloading." | "Reset" | "Reload" | "W" | "H" | "Upload Image" | "Search keyword" | "Select date" | "Locate in Chat" | "Select All" | "Confirm" | "Upload Image, up to 3 images supported, max 2.4MB each" | "Hello, I am BlueKing AI Bot" | "Clear Search" | "Search Result is Empty" | "Valid Evidence" | "Full Screen" | "Exit Full Screen" | "Please choose to continue" | "Continue" | "Received: " | "Done" | "Skip" | "Single" | "Multiple" | "Others" | "Answers" | "Replied" | "Please enter..." | "File Artifacts" | "File List" | "Search file keyword" | "Failed to load preview" | "No file to preview" | "发送" | "停止" | "问问小鲸" | "复制" | "分享" | "点赞" | "不满意" | "删除" | "引用" | "重新生成" | "重新生成将清空下文内容" | "提交" | "取消" | "预览内容" | "跳转详情" | "调用工具:" | "调用中" | "调用成功" | "调用失败" | "说出您的想法" | "什么原因让你满意?" | "什么原因让你不满意?" | "返回内容" | "编辑" | "深度思考" | "快速思考" | "图生文" | "图片加载中..." | "图片加载失败" | "思考中" | "已思考完成" | "思考失败" | "复制成功" | "复制失败" | "返回底部" | "停止生成" | "正在停止" | "耗时" | "参数" | "描述" | "执行情况" | "执行中" | "成功" | "失败" | "挂起" | "待执行" | "详情" | "重试" | "重试中" | "跳过中" | "任务正在重试中,不可跳过" | "任务正在跳过中,不可重试" | "节点" | "节点配置" | "节点输出" | "基础信息" | "流程模板" | "节点名称" | "步骤名称" | "执行方案" | "是否可选" | "失败处理" | "超时控制" | "是" | "否" | "输入参数" | "输出参数" | "参数名" | "参数值" | "名称" | "变量说明" | "结构化输出" | "手动跳过" | "暂无数据" | "调用 MCP:" | "更多" | "算法方案评审单" | "评审中" | "审批中" | "已废弃" | "已批准" | "已通过" | "已取消" | "已过期" | "已拒绝" | "已撤销" | "单据编号" | "提交时间" | "当前处理人" | "无" | "查看单据详情" | "复制单据" | "复制单据链接" | "取消审批" | "已取消审批" | "刷新单据状态" | "单据已取消审批" | "该单据已被拒绝,无法取消" | "该单据已通过,无法取消" | "单据已取消,无需重复点击" | "当前状态无法取消审批" | "当前会话有 {count} 个待审批单,如需继续,请先取消审批" | "暂不支持的中断消息" | "检索中" | "检索完成" | "上传文件" | "选择模型" | "搜索模型关键字" | "请求中..." | "取消满意" | "取消不满意" | "确认删除该回答?" | "删除操作无法撤回,请谨慎操作!" | "预览" | "缩小" | "放大" | "旋转" | "下载" | "抱歉,图片加载失败,可尝试重新加载" | "重置" | "重新加载" | "宽" | "高" | "上传图片" | "搜索 关键字" | "选择日期" | "在对话中定位" | "全选" | "确定" | "上传图片, 最多支持上传 3 个, 最大支持 2.4MB" | "你好,我是小鲸" | "清空搜索" | "搜索结果为空" | "有效证据" | "全屏" | "退出全屏" | "请选择以继续" | "继续" | "收到信息:" | "待审批" | "已审批" | "完成" | "跳过" | "单选" | "多选" | "其他" | "回答内容" | "已回复" | "请输入..." | "文件产物" | "文件列表" | "搜索文件关键字" | "预览加载失败" | "暂无可预览的文件";
159
+ export declare const t: (key: keyof typeof lang) => "Send" | "Stop" | "Ask AI" | "Copy" | "Share" | "Like" | "Unsatisfied" | "Delete" | "Quote" | "Regenerate" | "Regenerating will clear the content below" | "Submit" | "Cancel" | "Preview Content" | "Jump to Detail" | "Call Tool:" | "Calling..." | "Call Success" | "Call Failed" | "Tell us your thoughts" | "What makes you satisfied?" | "What makes you dissatisfied?" | "Return Content" | "Edit" | "Deep Thinking" | "Quick Thinking" | "Image to Text" | "Loading image..." | "Failed to load image" | "Thinking..." | "Thinking Completed" | "Thinking Failed" | "Copy Success" | "Copy Failed" | "Return to bottom" | "Stop generating" | "Stopping" | "Duration" | "Parameters" | "Description" | "Execution Status" | "Running" | "Success" | "Failed" | "Pending" | "To Be Executed" | "Details" | "Retry" | "Retrying" | "Skipping" | "The task is retrying and cannot be skipped" | "The task is skipping and cannot be retried" | "Node" | "Node Config" | "Node Output" | "Basic Info" | "Flow Template" | "Node Name" | "Step Name" | "Execution Plan" | "Optional" | "Failure Handler" | "Timeout Control" | "Yes" | "No" | "Input Params" | "Output Params" | "Param Name" | "Param Value" | "Name" | "Structured Output" | "Manual Skip" | "No Data" | "Call MCP:" | "More" | "Algorithm Plan Review Ticket" | "Reviewing" | "Approving" | "Abandoned" | "Approved" | "Cancelled" | "Expired" | "Rejected" | "Revoked" | "Ticket No." | "Submitted At" | "Current Handler" | "None" | "View Ticket Detail" | "Copy Ticket" | "Copy Ticket Link" | "Cancel Approval" | "Approval Cancelled" | "Refresh Ticket Status" | "This ticket has been rejected and cannot be cancelled" | "This ticket has been approved and cannot be cancelled" | "This ticket has been cancelled, no need to click again" | "Approval cannot be cancelled in the current status" | "There are {count} pending approval tickets in the current conversation. To continue, cancel approval first." | "Unsupported interrupt message" | "Searching" | "Search Completed" | "Upload File" | "Select model" | "Search models" | "Requesting..." | "Cancel satisfied" | "Cancel dissatisfied" | "Confirm delete this answer?" | "This operation cannot be undone. Please proceed with caution!" | "Preview" | "Zoom Out" | "Zoom In" | "Rotate" | "Download" | "Sorry, image loading failed. Please try reloading." | "Reset" | "Reload" | "W" | "H" | "Upload Image" | "Search keyword" | "Select date" | "Locate in Chat" | "Select All" | "Confirm" | "Upload Image, up to 3 images supported, max 2.4MB each" | "Hello, I am BlueKing AI Bot" | "Clear Search" | "Search Result is Empty" | "Valid Evidence" | "Full Screen" | "Exit Full Screen" | "Please choose to continue" | "Continue" | "Received: " | "Done" | "Skip" | "Single" | "Multiple" | "Others" | "Completed" | "question(s)" | "Answers" | "Replied" | "Please enter..." | "File Artifacts" | "File List" | "Search file keyword" | "Failed to load preview" | "No file to preview" | "发送" | "停止" | "问问小鲸" | "复制" | "分享" | "点赞" | "不满意" | "删除" | "引用" | "重新生成" | "重新生成将清空下文内容" | "提交" | "取消" | "预览内容" | "跳转详情" | "调用工具:" | "调用中" | "调用成功" | "调用失败" | "说出您的想法" | "什么原因让你满意?" | "什么原因让你不满意?" | "返回内容" | "编辑" | "深度思考" | "快速思考" | "图生文" | "图片加载中..." | "图片加载失败" | "思考中" | "已思考完成" | "思考失败" | "复制成功" | "复制失败" | "返回底部" | "停止生成" | "正在停止" | "耗时" | "参数" | "描述" | "执行情况" | "执行中" | "成功" | "失败" | "挂起" | "待执行" | "详情" | "重试" | "重试中" | "跳过中" | "任务正在重试中,不可跳过" | "任务正在跳过中,不可重试" | "节点" | "节点配置" | "节点输出" | "基础信息" | "流程模板" | "节点名称" | "步骤名称" | "执行方案" | "是否可选" | "失败处理" | "超时控制" | "是" | "否" | "输入参数" | "输出参数" | "参数名" | "参数值" | "名称" | "变量说明" | "结构化输出" | "手动跳过" | "暂无数据" | "调用 MCP:" | "更多" | "算法方案评审单" | "评审中" | "审批中" | "已废弃" | "已批准" | "已通过" | "已取消" | "已过期" | "已拒绝" | "已撤销" | "单据编号" | "提交时间" | "当前处理人" | "无" | "查看单据详情" | "复制单据" | "复制单据链接" | "取消审批" | "已取消审批" | "刷新单据状态" | "单据已取消审批" | "该单据已被拒绝,无法取消" | "该单据已通过,无法取消" | "单据已取消,无需重复点击" | "当前状态无法取消审批" | "当前会话有 {count} 个待审批单,如需继续,请先取消审批" | "暂不支持的中断消息" | "检索中" | "检索完成" | "上传文件" | "选择模型" | "搜索模型关键字" | "请求中..." | "取消满意" | "取消不满意" | "确认删除该回答?" | "删除操作无法撤回,请谨慎操作!" | "预览" | "缩小" | "放大" | "旋转" | "下载" | "抱歉,图片加载失败,可尝试重新加载" | "重置" | "重新加载" | "宽" | "高" | "上传图片" | "搜索 关键字" | "选择日期" | "在对话中定位" | "全选" | "确定" | "上传图片, 最多支持上传 3 个, 最大支持 2.4MB" | "你好,我是小鲸" | "清空搜索" | "搜索结果为空" | "有效证据" | "全屏" | "退出全屏" | "请选择以继续" | "继续" | "收到信息:" | "待审批" | "已审批" | "完成" | "跳过" | "单选" | "多选" | "其他" | "已完成" | "题" | "回答内容" | "已回复" | "请输入..." | "文件产物" | "文件列表" | "搜索文件关键字" | "预览加载失败" | "暂无可预览的文件";
@@ -381,7 +381,7 @@ AI 可在一次回复中发起多个工具调用,组件依次渲染:
381
381
  | `html` / `markdown` / `md` / `txt` / `json` | `download_url` | 正文直渲染(srcdoc / MarkdownContent / `<pre>`) |
382
382
  | `pdf` / `jpg` 等 | `preview_url` | iframe(一般为后台转好的 PDF) |
383
383
 
384
- `md` 与 `markdown` 等价(见 `AIFileType.Md` / `AIFileType.Markdown`)。
384
+ `md` 与 `markdown` 等价(见 `AIFileType.Md` / `AIFileType.Markdown`)。预览重载、`force` 重试与取链约定见 [FileArtifactPanel 预览机制](/components/message/file-artifact-panel#预览机制)。
385
385
 
386
386
  ```vue
387
387
  <template>
@@ -241,13 +241,14 @@ ai-chat-container(:data-ai-size="size")
241
241
 
242
242
  ### 内置「文件产物」Tab
243
243
 
244
- 除「执行情况」外,容器内置一个按需出现的固定 Tab —— **「文件产物」**(`name: 'file-artifact'`),用于聚合预览当前会话所有 `AssistantMessage.property.artifacts`:
244
+ 除「执行情况」外,容器内置一个按需出现的固定 Tab —— **「文件产物」**(`name: 'file-artifact'`),用于聚合预览当前会话所有 `AssistantMessage.property.artifacts`(按 `outputId` 去重):
245
245
 
246
- - **触发**:点击 AI 回复中的文件卡片([ArtifactFileCard](/components/message/assistant-message))时,容器通过 `useArtifactPreviewProvider` 命中该文件并 `addCustomTab` 弹出侧栏
246
+ - **静默挂载**:会话已有文件产物时,容器通过 `ensureCustomTab` 挂上该 Tab,**不展开侧栏、不切换当前选中**(避免从「执行情况」展开时被抢走焦点),并保证命中态有效(默认第一个 `outputId`)
247
+ - **主动打开**:点击 AI 回复中的文件卡片([ArtifactFileCard](/components/message/assistant-message))时,容器通过 `useArtifactPreviewProvider` 以 `outputId` 命中该文件,再 `addCustomTab` 展开侧栏并选中「文件产物」
247
248
  - **排序 / 关闭**:`order: -1` 排在「执行情况」之前,`closable: false` 不可关闭
248
249
  - **显隐解耦**:该 Tab 存在时,侧栏展示不再受「`executionGroups` 为空」约束(即使当前会话没有执行类消息,也能独立展示文件产物侧栏);会话切换或无文件产物时自动移除并重置命中态
249
- - **内容**:由 [FileArtifactPanel](/components/message/file-artifact-panel) 渲染列表与下载头,预览委托内部 `ArtifactPreviewHost`;`download_url` / `preview_url` 通过 `onArtifactClick` 异步获取。文本类(`html` / `markdown` / `md` / `txt` / `json`)拉 `download_url` 正文直渲染(`md` 与 `markdown` 等价);其余类型用 `preview_url` iframe(一般为后台转好的 PDF
250
- - **状态管理**:命中、切换与 URL 缓存由 [useArtifactPreview](/composables/use-artifact-preview) 提供(Provider 在容器内、Consumer 在文件卡片 / 面板内);正文加载与分类型渲染由 Host 内部完成
250
+ - **内容**:由 [FileArtifactPanel](/components/message/file-artifact-panel) 渲染列表与下载头,预览委托内部 `ArtifactPreviewHost`;`download_url` / `preview_url` 通过 `onArtifactClick` 异步获取。文本类(`html` / `markdown` / `md` / `txt` / `json`)拉 `download_url` 正文直渲染(`md` 与 `markdown` 等价);其余类型用 `preview_url` iframe(一般为后台转好的 PDF)。预览重载键为 `outputId:type`;失败重试会 `force` 绕过 URL 缓存
251
+ - **状态管理**:命中、切换与 URL 缓存由 [useArtifactPreview](/composables/use-artifact-preview) 提供(Provider 在容器内、Consumer 在文件卡片 / 面板内);正文加载与分类型渲染由 Host 内部完成;常规取链只传 `file`,勿传 `undefined` 作为第二参
251
252
  - **未传 `onArtifactClick`**:下载按钮隐藏,预览区展示无数据
252
253
 
253
254
  详见 [FileArtifactPanel 文件产物预览](/components/message/file-artifact-panel) 与 [useArtifactPreview 文件产物预览](/composables/use-artifact-preview)。
@@ -453,9 +454,9 @@ ai-chat-container(:data-ai-size="size")
453
454
 
454
455
  ## 用户问题中断
455
456
 
456
- 当会话中最近一条待处理 interrupt 包含 `InterruptReason.UserQuestion` 时,`ChatContainer` 会在 `ChatInput` 上方显示 [UserQuestionCard](/components/agent/user-question-card)
457
+ 当会话中最近一条待处理 interrupt 包含 `InterruptReason.UserQuestion` 时,`ChatContainer` 会在 `ChatInput` 上方显示 [UserQuestionCard](/components/agent/user-question-card)(一次一题,标题栏可切换题目)。
457
458
 
458
- - **结构化作答**:用户在卡片内完成选择或点击「跳过」后,通过 `onInterruptResume(payload, interrupt)` 回传 `UserQuestionResume`。
459
+ - **结构化作答**:用户在卡片内逐题选择(单选可自动跳下一题),点击「完成」或「跳过」后通过 `onInterruptResume(payload, interrupt)` 回传 `UserQuestionResume`。
459
460
  - **输入框发送**:用户也可在输入框直接点击发送;容器会调用 `onSendMessage(content, docSchema, options)`,其中 `options.interrupt` 为当前激活的 UserQuestion,`options.payload` 为 `buildSkipResumePayload` 生成的 skip resume(`status: 'cancelled'`,`answers: []`)。此时**不会自动清空**输入框,由业务侧在 `onSendMessage` 内决定如何处理 `content` 与中断恢复。
460
461
 
461
462
  ```vue
@@ -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 请求中)、MessageContentType、MessageToolsStatus、MessageState、Z-Index 与 CONST_MESSAGE_TOOLS 等导出常量。 用于构造消息、配置 MessageContainer 工具栏与输入态,以及层级与默认快捷指令。与类型 messages 配套使用。
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` 配合流式响应
@@ -1,7 +1,7 @@
1
1
  <!-- AI SUMMARY -->
2
2
  ## 快速了解
3
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。
4
+ 汇总当前会话所有 AssistantMessage 的 artifacts(按 outputId 去重),支持关键词搜索、列表选中与下载; 预览区委托 ArtifactPreviewHost:按类型走 text_from_download(html / markdown / md / txt / json) 或 preview_url_iframe(其余类型);download_url / preview_url 经 onArtifactClick 异步获取(TTL 缓存,重试 force); 预览重载键为 outputId:type;常规 resolveArtifactUrls 只传 file。 源码位置:src/components/chat-message/assistant-message/message-artifacts/file-artifact-panel.vue。
5
5
 
6
6
  ### 关联组件
7
7
  - **assistant-message** — 文件产物来源于 AssistantMessage.property.artifacts
@@ -22,16 +22,16 @@
22
22
 
23
23
  > **导出说明**:内部侧栏面板组件,**通常不直接使用**;由 `ChatContainer` 在「文件产物」Tab 内自动挂载。预览加载与渲染为同目录下 `artifact-preview/` 内部实现,不单独导出。
24
24
 
25
- 点击 AI 回复中的[文件卡片](/components/message/assistant-message)后,`ChatContainer` 侧栏会弹出固定的「文件产物」Tab,聚合展示当前会话**所有** `AssistantMessage` 的文件产物,并命中被点击的文件进行预览。
25
+ 点击 AI 回复中的[文件卡片](/components/message/assistant-message)后,`ChatContainer` 侧栏会弹出固定的「文件产物」Tab,聚合展示当前会话**所有** `AssistantMessage` 的文件产物(按 `outputId` 去重),并命中被点击的文件进行预览。
26
26
 
27
27
  面板左侧为可搜索的文件列表,右侧为预览区。通常不需要直接使用,由 `ChatContainer` 在侧栏内自动渲染。
28
28
 
29
29
  ## 核心能力
30
30
 
31
- - **会话级聚合**:拍平当前会话所有 `AssistantMessage.property.artifacts`,统一在一个列表内展示
32
- - **唯一命中**:同一会话可能出现多个消息 + 同名文件,文件名不可作唯一键,统一用 `messageUid#消息内下标#outputId` 生成全局唯一 id
31
+ - **会话级聚合**:拍平当前会话所有 `AssistantMessage.property.artifacts`,以 `outputId` 去重后统一在一个列表内展示
32
+ - **唯一命中**:以 `outputId` 作为会话内唯一键(同 `outputId` 视为同一文件);文件名可能重复,不可作唯一键
33
33
  - **关键词搜索**:按文件名实时过滤列表
34
- - **异步取链**:`AIFileInfo` 本身不含 `url` / `previewUrl`,通过 `ChatContainer` 的 `onArtifactClick` 按 `outputId` 缓存获取 `download_url` / `preview_url`
34
+ - **异步取链**:`AIFileInfo` 本身不含 `url` / `previewUrl`,通过 `ChatContainer` 的 `onArtifactClick` 按 `outputId` 获取 `download_url` / `preview_url`(TTL 8 分钟缓存;预览重试会 `force` 刷新)
35
35
  - **职责拆分**:
36
36
  - **面板本身**:列表、搜索、预览头(文件名 / 图标 / 下载)
37
37
  - **`ArtifactPreviewHost`**:按策略加载正文或预览 URL,分派到对应 renderer;展示 loading / empty / error(含重试)
@@ -54,12 +54,12 @@
54
54
 
55
55
  <script setup lang="ts">
56
56
  import { shallowRef } from 'vue'
57
- import { buildArtifactId, useArtifactPreviewProvider } from '@blueking/chat-x'
57
+ import { useArtifactPreviewProvider } from '@blueking/chat-x'
58
58
  import type { AIFileInfo, SessionArtifact } from '@blueking/chat-x'
59
59
  // 内部组件:仅文档 / 调试;业务请用 ChatContainer 自动挂载
60
60
  import FileArtifactPanel from './message-artifacts/file-artifact-panel.vue'
61
61
 
62
- const files: AIFileInfo[] = [
62
+ const sessionArtifacts: SessionArtifact[] = [
63
63
  { name: '周报.html', outputId: 'a-html', size: 10240, type: 'html' },
64
64
  { name: '说明.md', outputId: 'a-md', size: 8192, type: 'md' },
65
65
  { name: '纪要.txt', outputId: 'a-txt', size: 4096, type: 'txt' },
@@ -67,12 +67,6 @@
67
67
  { name: '立项.pdf', outputId: 'a-pdf', size: 204800, type: 'pdf' },
68
68
  ]
69
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
70
  useArtifactPreviewProvider({
77
71
  getOnArtifactClick: () => async file => {
78
72
  // 文本类返回可 fetch 的 download_url;iframe 类返回 preview_url
@@ -82,7 +76,7 @@
82
76
  onOpen: () => {},
83
77
  })
84
78
 
85
- const activeArtifactId = shallowRef(sessionArtifacts[0].artifactId)
79
+ const activeArtifactId = shallowRef(sessionArtifacts[0].outputId)
86
80
  const handleSelect = (id: string) => {
87
81
  activeArtifactId.value = id
88
82
  }
@@ -160,34 +154,32 @@
160
154
 
161
155
  ```
162
156
  ArtifactFileCard(点击文件卡片)
163
- └─ useArtifactPreviewConsumer().openPreview({ file, index, messageUid })
157
+ └─ useArtifactPreviewConsumer().openPreview({ file })
164
158
  └─ useArtifactPreviewProvider(ChatContainer 内)
165
- ├─ 记录命中文件 activeArtifactId
159
+ ├─ 记录命中文件 activeArtifactId = file.outputId
166
160
  └─ onOpen → addCustomTab('file-artifact') 展开并选中侧栏 Tab
167
161
  └─ FileArtifactPanel
168
- ├─ 列表 @select → setActiveArtifactId
162
+ ├─ 列表 @select → setActiveArtifactId(outputId)
169
163
  ├─ 下载 → resolveArtifactUrls + triggerArtifactDownload
170
164
  └─ ArtifactPreviewHost
171
165
  ├─ useArtifactPreviewLoader(策略 + fetch / 取链,防竞态)
172
166
  └─ HtmlPreview | MarkdownPreview | TxtPreview | UrlIframePreview
167
+
168
+ sessionArtifacts 有产物时
169
+ └─ ensureCustomTab('file-artifact') 静默挂上,不抢当前选中(如执行情况)
173
170
  ```
174
171
 
175
172
  - 文件卡片通过 `useArtifactPreviewConsumer` 注入预览上下文,无 Provider 时卡片不可点击(兜底 `undefined`)
176
173
  - `ChatContainer` 通过 `useArtifactPreviewProvider` 提供上下文,并把「打开侧栏 Tab」这一副作用以 `onOpen` 注入,保持 composable 职责单一
177
174
  - 侧栏「文件产物」Tab 固定不可关闭,`order: -1` 排在「执行情况」之前;会话切换或无文件产物时自动移除
178
175
 
179
- ## 唯一 id 规则
176
+ ## 唯一键规则
180
177
 
181
- 同一会话可能存在多个 `AssistantMessage`,且不同消息里可能有同名文件,因此**文件名不可作为唯一键**。统一由 `buildArtifactId` 生成:
178
+ 会话内以 **`outputId`** 作为文件产物唯一键:
182
179
 
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 侧聚合与文件卡片侧透传必须使用同一规则,保证命中一致。
180
+ - 同一 `outputId` 在多条消息中出现时,聚合列表去重并保留最后一次出现的文件信息
181
+ - `activeId`、列表 `:key`、`select` 事件参数均使用 `outputId`
182
+ - 文件名可能重复,**不可**作为唯一键
191
183
 
192
184
  ## 预览机制
193
185
 
@@ -211,7 +203,14 @@ Provider 侧聚合与文件卡片侧透传必须使用同一规则,保证命
211
203
  | `empty` | 「暂无可预览的文件」(无文件 / 未传 `onArtifactClick` / 缺所需 URL) |
212
204
  | `error` | 「预览加载失败」+ 重试按钮 |
213
205
 
214
- 切换文件时 `useArtifactPreviewLoader` 用 `loadSeq` + `AbortController` 中断上一次 `fetch`,避免竞态覆盖。下载图标仍由面板用 bkui `Loading` spin 单独表达。
206
+ ### 重载与取链约定
207
+
208
+ - **重载键**:`ArtifactPreviewHost` 以 `` `${outputId}:${type}` `` 监听文件变化;`outputId` 或 `type` 任一变化会重新 `load()`,仅改文件名等其它字段不会
209
+ - **常规取链**:`resolveArtifactUrls(file)`,只传文件,不传第二参
210
+ - **重试 / 强刷**:错误态点击重试走 `load({ force: true })` → `resolveArtifactUrls(file, { force: true })`,绕过 TTL 缓存重新取链
211
+ - **竞态**:切换文件时 `useArtifactPreviewLoader` 用 `loadSeq` + `AbortController` 中断上一次 `fetch`,避免过期结果覆盖最新内容
212
+
213
+ 下载图标仍由面板用 bkui `Loading` spin 单独表达。
215
214
 
216
215
  ## 内部结构(不导出)
217
216
 
@@ -235,14 +234,14 @@ message-artifacts/
235
234
 
236
235
  | 属性名 | 类型 | 必填 | 说明 |
237
236
  | --------- | ------------------- | ---- | -------------------------------------- |
238
- | activeId | `string` | ✓ | 当前命中的文件 id(`messageUid#index#outputId`) |
239
- | artifacts | `SessionArtifact[]` | ✓ | 当前会话全部文件产物 |
237
+ | activeId | `string` | ✓ | 当前命中的文件 `outputId` |
238
+ | artifacts | `SessionArtifact[]` | ✓ | 当前会话全部文件产物(已按 `outputId` 去重) |
240
239
 
241
240
  ### Events
242
241
 
243
242
  | 事件名 | 参数 | 说明 |
244
243
  | ------ | ----------------- | -------------------------- |
245
- | select | `(id: string)` | 列表内切换选中文件,参数为文件 `artifactId` |
244
+ | select | `(id: string)` | 列表内切换选中文件,参数为文件 `outputId` |
246
245
 
247
246
  ### Slots / Expose
248
247
 
@@ -253,11 +252,8 @@ message-artifacts/
253
252
  ```typescript
254
253
  import type { AIFileInfo, SessionArtifact } from '@blueking/chat-x';
255
254
 
256
- // 会话级文件产物:在 AIFileInfo 基础上补充命中所需字段
257
- type SessionArtifact = AIFileInfo & {
258
- artifactId: string; // 全局唯一 id:messageUid#index#outputId
259
- messageUid: string; // 所属 AssistantMessage 的 uid
260
- };
255
+ // 会话级文件产物:拍平去重后即为 AIFileInfo
256
+ type SessionArtifact = AIFileInfo;
261
257
 
262
258
  type AIFileInfo = {
263
259
  name: string;
@@ -20,16 +20,17 @@
20
20
 
21
21
  > **导出说明**:`InfoMessage` **未**从包入口导出(入口同名是 TS interface)。消费方经 `MessageRender` / `MessageContainer` 使用。下文 `InfoMessageComp` 为文档站内部示例。
22
22
 
23
- 系统信息分隔组件,在聊天消息列表中以**居中虚线分隔条**的形式展示非对话类信息(会话重置、时间节点、状态变更等)。
23
+ 系统信息分隔组件,在聊天消息列表中以**左右虚线夹中文案**的形式展示非对话类信息(会话重置、时间节点、状态变更等)。
24
24
 
25
25
  ## 视觉原理
26
26
 
27
- 组件通过 `height: 0` + `border-bottom: 1px dashed #dcdee5` 生成一条贯穿全宽的虚线,内容文字区域设置白色背景"浮"在虚线中央,形成"文字刻在分隔线上"的视觉效果:
27
+ 根节点 `.ai-info-message` 为横向 flex:两侧通过 `::before` / `::after` 拉伸出虚线(主题边框色),中间 `.ai-info-message-body` 承载文案(主题次要文案色)。整块正常占位,避免旧实现 `height: 0` 导致内容被裁切遮挡:
28
28
 
29
29
  ```
30
- ───── ─ ─ 以下是新的对话 ─ ─ ─────
30
+ ─────── 以下是新的对话 ───────
31
31
  ```
32
32
 
33
+ 多行时,多条 `.ai-info-message-content` 在 body 内纵向排列(`gap: 4px`),两侧虚线仍夹住整块文案区域。
33
34
  ## 基础用法
34
35
 
35
36
  `content` 传入字符串,渲染单行分隔信息:
@@ -56,7 +57,7 @@
56
57
 
57
58
  ## 多行信息
58
59
 
59
- `content` 传入字符串数组时,每个元素渲染为一个独立的文字浮标,均居中排列在同一条虚线上:
60
+ `content` 传入字符串数组时,每个元素渲染为一行居中文案,在中间 body 内纵向排列,两侧虚线夹住整块区域:
60
61
 
61
62
  ```vue
62
63
  <template>
@@ -134,7 +135,7 @@
134
135
 
135
136
  | 属性名 | 类型 | 说明 |
136
137
  | --------- | -------------------- | ------------------------------------------------------------------ |
137
- | content | `string \| string[]` | 信息内容。字符串渲染单行,数组渲染多个文字浮标,均居中排列在虚线上 |
138
+ | content | `string \| string[]` | 信息内容。字符串渲染单行;数组在中间区域纵向多行展示,两侧虚线夹住整块 |
138
139
  | id | `number \| string` | 消息 ID(接收但不使用,由 MessageContainer 管理) |
139
140
  | messageId | `number \| string` | 消息唯一标识(接收但不使用) |
140
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
 
@@ -613,29 +613,12 @@ enum MessageToolsStatus {
613
613
  Hidden = 'hidden',
614
614
  }
615
615
 
616
- // 消息角色
617
- enum MessageRole {
618
- User = 'user',
619
- Assistant = 'assistant',
620
- Tool = 'tool',
621
- Reasoning = 'reasoning',
622
- Activity = 'activity',
623
- Info = 'info',
624
- Interrupt = 'interrupt',
625
- Loading = 'loading',
626
- }
627
-
628
- // 消息状态
629
- enum MessageStatus {
630
- Pending = 'pending',
631
- Streaming = 'streaming',
632
- Complete = 'complete',
633
- Error = 'error',
634
- Stop = 'stop',
635
- Disabled = 'disabled',
636
- }
616
+ // 消息角色 / 消息状态完整枚举见常量文档,勿在此维护副本
617
+ // MessageRole、MessageStatus → ../../types/constants
637
618
  ```
638
619
 
620
+ > `MessageRole` / `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。
621
+
639
622
  ## 关联组件
640
623
 
641
624
  - [MessageRender](/components/message/message-render) — 按组渲染每条消息时委托使用
@@ -315,35 +315,12 @@ h(ContentRender, { content: message.content || '', status: message.status }, /*
315
315
  ```typescript
316
316
  import { MessageRole, MessageStatus, MessageToolsStatus, type Message, type IToolBtn } from '@blueking/chat-x';
317
317
 
318
- // 消息角色
319
- enum MessageRole {
320
- User = 'user',
321
- Assistant = 'assistant',
322
- Info = 'info',
323
- Reasoning = 'reasoning',
324
- Tool = 'tool',
325
- Activity = 'activity',
326
- Loading = 'loading',
327
- Interrupt = 'interrupt',
328
- }
329
-
330
- // 消息状态
331
- enum MessageStatus {
332
- Pending = 'pending',
333
- Streaming = 'streaming',
334
- Complete = 'complete',
335
- Error = 'error',
336
- Stop = 'stop',
337
- Disabled = 'disabled',
338
- }
339
-
340
- // 工具按钮状态(仅转发给 UserMessage)
341
- enum MessageToolsStatus {
342
- Disabled = 'disabled',
343
- Hidden = 'hidden',
344
- }
318
+ // MessageRole / MessageStatus 完整枚举见 ../../types/constants
319
+ // MessageToolsStatus:Disabled | Hidden(仅转发给 UserMessage)
345
320
  ```
346
321
 
322
+ > `MessageRole` / `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。
323
+
347
324
  ## 关联组件
348
325
 
349
326
  - [MessageContainer](/components/setup/message-container) — 内部按组调用以渲染每条消息
@@ -144,6 +144,9 @@ enum MessageStatus {
144
144
  // 已完成
145
145
  Complete = 'complete',
146
146
 
147
+ // 已完成(与 Complete 同义,兼容协议/后端返回的 completed)
148
+ Completed = 'completed',
149
+
147
150
  // 已禁用
148
151
  Disabled = 'disabled',
149
152
 
@@ -170,6 +173,8 @@ enum MessageStatus {
170
173
  }
171
174
  ```
172
175
 
176
+ 完整取值与说明见 [常量枚举 · MessageStatus](./constants#messagestatus)。
177
+
173
178
  ## 具体消息类型
174
179
 
175
180
  ### UserMessage
@@ -224,17 +224,10 @@ interface ReasoningMessage {
224
224
  duration?: number; // 推理耗时(毫秒)
225
225
  name?: string;
226
226
  }
227
-
228
- enum MessageStatus {
229
- Pending = 'pending',
230
- Streaming = 'streaming',
231
- Complete = 'complete',
232
- Success = 'success',
233
- Error = 'error',
234
- Stop = 'stop',
235
- }
236
227
  ```
237
228
 
229
+ > `MessageStatus` 完整取值见 [常量枚举](../../types/constants)。本组件完成态识别 `complete` / `success`(与标题文案表一致)。
230
+
238
231
  ## 关联组件
239
232
 
240
233
  - [MessageRender](/components/message/message-render) — reasoning 角色由其实例化
@@ -78,14 +78,14 @@
78
78
 
79
79
  `status` prop 同时控制头部的 CSS class(`toolcall-status-{status}`)、背景/边框颜色、状态文案和 Loading 动画:
80
80
 
81
- | `status` | 状态文案 | 背景色 | 边框色 | Loading |
82
- | ----------------------- | -------- | ----------------- | --------- | ------- |
83
- | `pending` / `streaming` | 调用中 | `#fafbfd` | `#dcdee5` | ✓ |
84
- | `complete` / `success` | 调用成功 | `#ebfaf0` | `#a1e3ba` | - |
85
- | `error` | 调用失败 | `#fff0f0` | `#f8b4b4` | - |
86
- | 其他 / `undefined` | 调用中 | —(无匹配 class) | — | - |
87
-
88
- > **说明**:`statusTitle` `switch` 语句中 `default` 与 `case Pending` 共享同一返回值,`streaming` 和未知 status 均命中 `default` 分支,显示"调用中"。Loading 动画由 `v-if="status === 'pending' || status === 'streaming'"` 单独控制。
81
+ | `status` | 状态文案 | 背景色 | 边框色 | Loading |
82
+ | ------------------------------------- | -------- | ----------------- | --------- | ------- |
83
+ | `pending` / `streaming` | 调用中 | `#fafbfd` | `#dcdee5` | ✓ |
84
+ | `complete` / `completed` / `success` | 调用成功 | `#ebfaf0` | `#a1e3ba` | - |
85
+ | `error` | 调用失败 | `#fff0f0` | `#f8b4b4` | - |
86
+ | 其他 / `undefined` | 调用中 | —(无匹配 class) | — | - |
87
+
88
+ > **说明**:`statusTitle` `Completed`(`completed`)与 `Complete` / `Success` 一并视为成功;主题 `$toolcallStatusMap` 同步提供 `completed` 色值。`default` 与 `case Pending` 共享「调用中」文案,`streaming` 与未知 status 命中 `default`。Loading `v-if="status === 'pending' || status === 'streaming'"` 控制。
89
89
 
90
90
  **三种状态对比**
91
91