fix(chat): preserve retry attachments and per-answer context snapshots

This commit is contained in:
2026-09-07 00:09:14 +08:00
parent 11e5785681
commit ac2d36bf9c
10 changed files with 106 additions and 5 deletions
@@ -1609,3 +1609,7 @@ CUDA 组件:`GET /api/local-models/runtime-components/cuda` 返回 status、st
`/api/media/attachments` 新增允许 DOCX、PPTX、PPT、PNG、JPG/JPEG、WebP 后缀。聊天通过 `ChatRequest.attachments` 提交最多 8 个持久化附件 ID,并通过 `ChatMessage.attachments` 恢复记录。`image_fallback_tools` 最多两个注册工具名,服务端固定 MCP 优先、Plugin 次之,不接受任意命令或远程下载 URL。
内部模型 `Message.images` 使用有大小限制的 PNG/JPEG/WebP base64 data URIProvider 适配器转换为各自原生协议。文档和音频提取为参考文本后才交给普通聊天,清除已解析的二进制附件标记,使文本上下文检测仍可工作。附件失败返回 `CHAT_ATTACHMENT_FAILED`,进度与截断提示使用 `ContextStatus`,不将失败附件当作已读取内容。
#### 回答版本的上下文快照(2026-09-07)
`ChatMessage.context_captured` 为布尔值,旧记录默认 false。新 assistant 消息保存本次请求的 `workspace_context``attachments`,并设置 context_captured 为 true;此时 null 文件上下文和空附件列表都是明确快照。重新生成不覆盖原 user 消息的快照。客户端恢复旧记录时仅在 context_captured 为 false 时回退到对应父用户消息。
@@ -93,3 +93,11 @@ AI 消息提供“重新生成”,用户消息提供“编辑”及“保存
内置 `chat-operator` Skill 与 `chat-policy` Plugin 随 Host 注册。Plugin 的 `chat-policy.plan` 使用宿主白名单 handler 校验任务与预算,生成读取、执行和核验步骤,不执行任意插件代码。聊天委托创建运行前调用检查;启用的 Skill 加入聊天系统提示词并作为委托运行的 Skill,权限继续由 Agent 管理。用户禁用扩展后不会自动重新启用。
新增验证:`test_chat_attachments.py` 覆盖 Office/Markdown 文本抽取、旧 PPT 文本记录、截断、音频任务路由、原生视觉优先及 MCP 超时后 Plugin 降级;浮窗测试覆盖尺寸记忆和重置。浏览器实测折叠设置、上传入口和拖动缩放。未使用真实外部模型或 MCP 服务进行付费调用验收。
### 重试上下文与历史版本一致性(2026-09-07)
编辑旧用户消息使用该消息的附件;重新生成回答使用该回答版本实际使用的附件和文件快照。旧版未记录回答快照时才回退到它的父用户消息,不读取会话末尾其他轮次的附件。重试不会消耗输入区尚未发送的新附件。
新回答将 `workspace_context``attachments``context_captured=true` 一起持久化。原用户消息保持不变,因此同一问题的不同回答可以各自恢复生成时的文件内容;工作区浮窗显式传入当前文件时,以本次文件为准。`context_captured=true``workspace_context=null` 表示该版本明确未附带文件,继续对话或重试时不能回退到原用户消息的旧文件。数据库迁移为既有消息设置 false,保持旧记录可恢复。
回归覆盖:两轮使用不同附件后编辑/重试第一轮、保留待发送附件、切换工作区文件后生成新版本、历史回读后继续重试、明确清空文件上下文、原版本快照保持不变。