Repository navigation
fix(chat): restore files on saved original replies - #8476
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
接收已回传文件、随后在 App 对话或完整答复页读取结果的用户。 同一条已送达的答复,旧版两处均无文件入口;本次从原结果恢复下载入口,用户无需重发请求。 对话与完整答复页都能下载原文件,中文名称和原始字节保持一致。 本次不改变任务执行、消息发送、输入附件准入、群组披露或跨主机文件传输。 合入后的真实安装采用与原会话下载验收仍由维护者完成;其他未答请求不由此判为完成。 这是有完整读取闭环的增量,不以测试数量替代用户可取得原文件这一结果,也不把原业务请求重新执行当作恢复。
改动思路 / Approach
复用既有发布身份、字节读取和历史投影,新增代码只连接原消息与下载消费;没有第二份授权、文件库或迁移写入。 当前 PR 完整交付已发布文件在原 App 两个阅读入口的只读访问;实际安装验收单独跟进,其他任务执行保持原 owner。 最强的反对理由是:新增下载接口可能绕开原受众,或者变成另一套文件发布系统。这里先沿原 Session、Turn、回传路由和接收者条目定位不可变结果,再交给已有 TypeScript 结果身份规则,下载时再由已有字节读取器校验。仅改前端没有可用元数据;重发会引入重复效果;批量改写历史则增加迁移与同步责任,因此当前投影加薄 HTTP 适配器更小。原发布仍由接收者执行,页面只读。
| 原触发 | 旧版观察 | 当前头观察 |
|---|---|---|
| 打开已经完成且带文件的原答复 | 正文存在,两处文件入口均为零 | 对话和完整答复均可逐字节下载 |
| 错消息、来源变化或文件损坏 | 无此下载接口 | 404/403/503,保留原结果与发送凭证 |
这张表根据实际旧版与当前等价源树测试整理;当前精确头 19481f876f0f2aa7b355aed42e6e919c3b355ffc 与截图源头 f6ce569f9fbcd860502d98196f9f7b956cd21a55 的完整 Git tree 相同。
具体改动 / Changes
依据既有 manager-context 文件与恢复契约,spec_ref 为 loopx/capabilities/manager_context/README.md,spec_revision 为 e7ae4b077c0a2da0791753c9be3f7e4ff0b59b6e。RF-source 对应原受众、原工作区和同一次结果发布;RF-bytes 对应快照身份与原始字节;RF-effects 对应读回不能重发;RF-boundary 将群组、跨主机和视频继续留在既有资格范围外。前三项在当前头实现并验证,最后一项不在本次扩展范围。原文此前的发布阶段没有认证本地 Web 呈现,本次以真实 App/HTTP 入口单独验证原消息读取,不借它扩大发布权限。
关键代码讲解
project_chat_return_deliveries继续优先使用原 Turn 中的请求定位,只把本页已选中的结果交给回调。文件字段是派生投影,原消息日志和发布凭证不被改写;原有历史 fallback 和非本页结果过滤仍走同一入口。read_chat_return_file从保存的原manager_followup消息开始,忽略其中可能存在的输入附件定位,再验证原 Session、Turn、route 和共享结果身份。文件标识包含摘要与原位置,相同字节的不同名称不会混为一项,最终读取复用read_result_file。ChatResultFilesRequestMixin只负责同源原消息 GET、错误映射和下载响应头;使用原文件名、octet-stream、no-store 与 nosniff,不承担发布或重试决策。DocumentAttachment只为严格匹配的原消息文件 URL 渲染下载链接。对话与完整答复复用它,原纯文本/Markdown 输入预览和 MIME 准入继续保留。未加入 composer、排队消息或原问题视图的无关改动。
全差异为 452 行新增、15 行删除,其中生产代码127行新增/8行删除,测试266行新增/7行删除,文档59行新增;没有生成资产或新文件库。历史消息可长期缺少 canonical attachments,因此不能删除旧数据兼容或改成只支持新回复;当前只读派生比迁移写入更可控。
对主干的风险 / Risks
未发现阻塞性的代码缺陷。最重要的反例是“猜到摘要即可读到其他会话的私有文件”:实际入口负例覆盖错 Session/原消息、原 channel/client Turn 被改、无关 Origin 和快照字节被替换,分别拒绝为404、403或503;输出 URL 也不能作为新输入附件获得准入。另一个容易漏掉的情形是两个不同文件字节相同,测试独立核对各自响应文件名,避免只验证哈希却丢掉名称。
PASS:集成主干后的历史回传135项、既有飞书文件48项、原回复上下文页面回归、完整 App/Chat 构建,以及当前签署头的标准预合并6+13项。打包场景使用真实结果发布、SQLite、Chat HTTP和实际页面,两处下载均逐字节一致,模型 Turn 为0,provider发送仍为原来1次,原日志与凭证不变。provider/model 身份为合成,不能代替安装后的个人会话验收。初次预合并缺根 TypeScript 依赖的真实失败已保留,锁定安装后同一标准检查通过,未提高上限或删除断言。旧提案 #8475 的手工合并提交漏签署尾注,已保留并由本提案替代;两条当前贡献提交均有 DCO,完整源树相同,未强推。
语义与 CI 对齐
当前使用既有结果身份、附件及回传状态词汇,没有新增生命周期枚举、第二权威或工作义务。当前策略 wait_for_ci=false,因此没有获取、轮询或等待远端 CI;旧提案的自动 DCO 提示只作为历史诊断,不冒充当前 CI 通过。正常无文件结果、原输入和历史分页/旧路由 fallback 仍由135项回归覆盖。合并资格与这里的代码判断分开,仍须对当前头读取 readiness 和 review threads。
我的整体评价 / Verdict
结论为 APPROVE,交付判断为 justified_increment。long_horizon improved:原结果可持续读取,后续打开不会再制造任务执行或重复发送;user_experience improved:已知授权与意图下新增确认轮次为0。文件入口与原答复相邻,桌面首屏能看到文件名与大小;窄屏完整答复仍按正文、文件、来源详情排列,来源保持可展开,未增加重复解释或缩小正文。 合成画面证明所审源树的布局;真实用户安装后的原会话尚待采用验收,未宣称 Windows 实测或整个历史长列表的视觉覆盖。 版式判断来自实际图像检查,不把链接计数或无溢出断言当作可读性证明。
这次机制、默认范围与失败责任相称;保留已有规则和兼容是由真实历史记录驱动,没有新版本解码器或同步状态。当前源代码路径已形成可用的文件读取闭环,安装采用及原文件独立比对留作明确的后续验收,不能据此关闭其他业务积压。
English verdict: APPROVE — head 19481f8; original-result downloads are source-bound and byte-exact, with no rerun or resend. Local validation passed; live installed adoption remains separate.
原结果已经带文件完成回传时,App 保存的消息仍可能没有附件,用户在对话和完整答复页都无法下载。现在从原 Session、Turn、回传路由及已发布结果投影下载入口;下载重新校验不可变快照的大小与 SHA-256,并保留原文件名。相同字节的不同文件也保留各自名称。
复用已有结果发布规则、附件字段和文档组件。原消息、发布凭证及输入附件准入保持原样,浏览不会再次执行 Agent 或发送结果。错会话、来源变化、越界来源和文件损坏有独立负例。
验证:集成最新 main 后,历史回传模块 135 项通过;原飞书结果文件 48 项通过;原回复上下文页面回归通过;打包场景验证两处逐字节下载、中文名称、BOM/CRLF、二进制、键盘、窄屏及英文,零模型 Turn、发送仍为原来的一次;完整 App/Chat 构建及标准预合并 6+13 项通过。初次预合并因本地根目录缺 TypeScript 依赖失败,安装锁定依赖后通过。CI 按当前项目策略不查询或等待。
视觉与数据边界:使用可复现的合成原会话、真实发布和 SQLite/Chat HTTP 及打包 UI。旧版 37aaff7 复现两处缺文件,修复后下载入口直接显示在原答复旁;完整答复与来源详情仍保留。已检查桌面及窄屏画面和 PNG 元数据,无个人对话或私密证据。真实安装采用与原会话验收将在合入后完成。
复现见 docs/development/returned-files-readback.md。
视觉证据 / Visual evidence(修复头
f6ce569f9fbcd860502d98196f9f7b956cd21a55;对照37aaff7a035d0df18b2166cfe0dc74d5fe04eaf7):签署记录修复:替代 #8475。原 PR 的手工主干合并提交漏了 DCO 尾注;此分支仅保留两条已签署的贡献提交,与
f6ce569f9fbcd860502d98196f9f7b956cd21a55的完整 Git tree 相同,前述测试与截图均可复用。当前头为19481f876f0f2aa7b355aed42e6e919c3b355ffc,没有改写原分支。