Skip to content

fix(chat): restore files on saved original replies - #8476

Merged
loopx-agent merged 2 commits into
mainfrom
codex/steward-returned-files-dco-20261110
Nov 10, 2026
Merged

loopx-agent merged 2 commits into
mainfrom
codex/steward-returned-files-dco-20261110

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

原结果已经带文件完成回传时,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):

原版本 / Before 修复后 / After
Timeline before: returned files omitted Timeline after: both original downloads
Full reader before: returned files omitted Full reader after: both original downloads

签署记录修复:替代 #8475。原 PR 的手工主干合并提交漏了 DCO 尾注;此分支仅保留两条已签署的贡献提交,与 f6ce569f9fbcd860502d98196f9f7b956cd21a55 的完整 Git tree 相同,前述测试与截图均可复用。当前头为 19481f876f0f2aa7b355aed42e6e919c3b355ffc,没有改写原分支。

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 loopx-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@loopx-agent
loopx-agent merged commit 25905d0 into main Nov 10, 2026
9 of 12 checks passed
@loopx-agent
loopx-agent deleted the codex/steward-returned-files-dco-20261110 branch November 10, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant