Repository navigation
fix(chat): return verified native answers from empty final responses - #8497
Conversation
…without replay 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.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
结论:APPROVE。已重新审查精确 head fe82148778be76b6956169e6652208943711fb36 的全部五文件,以及共享 parser、原生证明、Core 与原 outbox 调用者;当前没有剩余阻断项。作者自审以 COMMENTED 保存,不冒称另一名独立审查人。
Reviewer: actor_kind=model_agent; model=gpt-6.1-sol; provider=OpenAI; declaration_source=runtime_reported; reasoning_effort=max
动机 / Motivation
原生助手已经正常结束并生成正文,原用户却只看到仍在生成的草稿,因为省略 message 的末尾元数据被保存成了空答复。
同一条原生请求,以前完成后仍等不到最终回传;现在核验该原输入与原生终态后,原服务把已有答复补回原消息。
用户不必重述任务或重做已经发生的业务,就能收到原执行生成的最终正文。
本 PR 不修复上游 EOF、不启动新模型或重放业务、不改写原 Turn/events,也不证明原答复中业务结论的正确性。
正常安装采用、原服务自然补回与客户端读回仍属于后续验收;上游 EOF 和其他积压业务继续由各自原 owner 负责。
问题发生在执行结束之后。再运行一次模型或要求用户重述任务,既不能修复原回传,也会增加重复效果风险。这个增量使原结果走完既有返回路径;不是对业务内容正确性或所有历史欠办的笼统完成声明。已有意图与授权足够,不新增确认、复制、导航或准备轮次。
改动思路 / Approach
已核验最终步骤的原生适配器拥有正文出处,通用 parser 不拥有这个出处。保留通用契约,在原生边界复用 envelope locator 与一次原脱敏,再沿既有 Core 结果采用和原 outbox 返回,是更小且更准确的责任划分。
当前 PR 交付已核验原生纯文本的保留及存量空终态的原结果回传;操作元数据、业务执行、上游恢复和其他提供方都保留原 owner 与门禁。
最强反例是:一看到缺 message,就把任意前缀当作最终答复或 compact 元数据。这会破坏其他提供方的既定规则,已有 parser 用例实际捕获了3项回归。因此最终 chat.py 与 base 完全一致;仅两个已核验正常终态的原生调用者可以走纯文本回退。已存在的 proposals、委派、Gate、protected action、goal draft 或 unfinished work 都阻止这条回退,仍由原 typed owner 处理。
下表是该 head 的源码分支说明,执行证据另列在风险段落;不把表格当作生产成功证据。
| 入口与条件 | 原行为 | 当前行为 | 保留边界 |
|---|---|---|---|
| 通用前缀/合法元数据 | 原 parser 规则 | 完全相同 | 缺字段不是 compact 信号 |
| 已核验原生最终步骤,无 typed metadata | 空正文 | 保留该最终步骤的纯文本 | 仅一次原脱敏,不取前序 commentary |
| 存量原生 completed/empty,无回执 | 永久跳过空串 | 核验原结果后沿原 terminal 返回 | 不入队、不跑模型、不重做业务 |
| 改源/关闭/停止/无原生证明 | 保持原请求 | 仍保持 | 不把等待变成放权 |
| 已开始发送但无 locator | 原 intent 未确认 | 仍未确认 | 重启不再发一次 |
具体改动 / Changes
_parse_native_final_response 只由 _run_turn 的严格正常终态和 completed_result_observation 的精确原输入/终态读回调用。先保留通用解析结果;只有正文空且没有任何 typed 操作、Gate 或未完声明时,才用已有 _review_openings 找到该最终响应的正文,并交回同一个原 parser/redactor。没有新 envelope decoder。用 stream filter 做第二次过滤曾把本地链接重复脱敏,已由独立路径断言捕获并改为共享 locator,未放宽断言。
planContextRecovery 只允许原生已提交、completed/empty、pure result 的原请求在尚无终态回执时进入既有结果采用;并不放开其他失败族。原 session/Turn/message、App/owner/grant、输入锚点、正常 final、停止和队列条件继续核验,缺完整证明不推断“没有效果”。extendsOriginalText 对空原文的允许仅服务同一无操作结果扩展;非空原文的前缀及元数据一致性保留。
Core.todo_confirmation_reply 和现有候选 owner 负责结果选择,Lark 不再自己判断原生事实。既有 native_result_recovery 冻结原结果并追加其稳定消息身份,原空 Turn/events 保留。原 reconcile_request 仍使用同一个来源核验、draft/final intent、provider readback 与重启恢复路径,没有第二消费者。最后 record_delivery 在同一 Core 请求 fence 下只为同 Turn、精确冻结正文结算 native-result receipt;其他正文不能替它作证。
规格固定在 docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md 的 559cb354fc4f8670f26e88dee38136c42757735a。compact-envelope-boundary 对应显式空 message 与缺失/null 的区别;operation-bound-source 对应每次发送及恢复的原来源/Core grant 核验;unknown-send-preserved 对应无 locator 的未知发送仍保持未确认。这些是段落描述性标签,不是新造的 RFC 编号。三项按未修改的接受文本审查,没有重写规格以迁就实现,也没有把其后续路线图当成本 PR 的义务。
对主干的风险 / Risks
最终同一 fixture 在不可变 base 上 5 failed /15 passed,在该 head 上 20 passed,覆盖未来原生最终响应、9个合法元数据对照、已有空结果、改源/关闭/停止、不可核验原生结果与 lost-ack。结果采用的正例实际经过 localhost native RPC、生产适配器、真实 CoreFileStore、typed TypeScript owner 和原 Lark 类;测试禁止新 enqueue、resume 和 model start,核原受众、原 Turn/events 字节及重启零第二次写入。没有把 fixture 直接供给最终 Core 后置状态当作证明。
最终 native-adapter 与 shared-parser 两文件 192 passed,前后源码哈希一致;Core/TS/Lark 三个文件与前一精确版本的 owner 回归代码完全一致,保留其619项通过观测。那次整体试跑的3个共享 parser 失败是本 PR 的真实回归,已通过还原通用规则和最终192+20项验证解决,未伪装为预先存在。旧全量试跑的中止、test-only cleanup 错误与中间路径脱敏失败均保留为历史,未当作最终资格。
6项直接、10项选中 premerge 检查、TypeScript 全量 typecheck、ruff、提交后的 RFC 双语与 diff 检查通过,最终五文件公开边界扫描零错误/零警告。普通 mypy 遍历导入图仍有4809项诊断;同一命令在不可变 base 和最终源码按文件、完整诊断与源码上下文逐条一致,无 head-only 项,未冒称全仓类型全绿。按当前 Goal 策略未查询、轮询或等待 CI;CI 没有被当作本地不变量的替代证据。
总差异167+/16-,其中116行是既有文件的回归用例,没有新服务、状态版本、配置或迁移。私聊文件保持2189行,低于2191的既有上限,没有以抬上限通过检查。外部模型和 Lark 网络仍是 fixture;只读真实留存证明能恢复正文,不代表已在线投递或已验证业务内容。回滚不必重写原失败/空终态或历史 receipt,未知发送依旧保持原 intent。
我的整体评价 / Verdict
已核验最终步骤的原生适配器拥有正文出处,通用 parser 不拥有这个出处。保留通用契约,在原生边界复用 envelope locator 与一次原脱敏,再沿既有 Core 结果采用和原 outbox 返回,是更小且更准确的责任划分。
当前 PR 交付已核验原生纯文本的保留及存量空终态的原结果回传;操作元数据、业务执行、上游恢复和其他提供方都保留原 owner 与门禁。
这个边界解决了实际的无限收尾等待,且没有让用户承担新的准备或确认成本;原执行与返回的责任保持分开。原生正文的出处和结果状态有独立核验,通用协议、合法元数据及未知效果都保留原含义。正常采用与原服务的真实回传继续按既有维护流程验收;本批准不授权重放、其他 PR 合并或任何更宽的业务操作。
检查了原生响应、Core.todo_confirmation_reply 与既有 Lark plain-post/outbox 路径;没有页面、组件、布局、渲染模板、标签或折叠改动,渲染展示审查不适用。
尚未把离线 fixture 正文当作真实 Lark 客户端视觉验收;安装后的自然原消息回传仍需独立读回。
English verdict: APPROVE — exact head fe82148778be76b6956169e6652208943711fb36; verified native text and original result return are covered by20 same-fixture counterfactual cases,192 final native/parser tests and local premerge checks. Generic metadata rules and no-replay fences remain; live adoption is separate and CI was not consulted.
Goal And Delivered Outcome
原生助手已正常结束并生成正文,但末尾 envelope 省略
message,原适配层直接采用通用解析结果,Core 因此保存 completed/empty,原回传又持续跳过空串。修复在已核验的原生最终步骤保留纯文本,并让原服务采用严格核验的留存结果补最终回传。通用解析器刻意不把无关前缀当答复,本 PR 最终没有改动它。缺字段也不选择 compact 元数据约定:仅当解析结果没有任何操作、委派、Gate 或未完声明时,原生 owner 才保留该最终步骤的可见正文。合法元数据与 Codex 行为保持原样。
Author Declaration
docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md,revision559cb354fc4f8670f26e88dee38136c42757735a。下列为段落的描述性标签,不是新造的 RFC 编号。compact-envelope-boundary:仅显式空 message 选择正文复用与 typed metadata;缺失/null 不选择该约定chat.py与 base 完全一致;9 项合法元数据对照和完整 response-parsing suite。operation-bound-source:每次发送/恢复按原 App、绑定、来源与 Core grant 核验unknown-send-preserved:无 locator 的未知发送在重启后保持未确认,不重发Scope And Continuation
未来原生答复在终态边界保留正文;存量未回传 completed/empty 只采用精确原输入锚点、正常原生终态、当前来源与停止/队列核验过的无操作结果,沿原 terminal outbox 返回。Core 负责候选、正文选择及匹配文本 receipt 的原子结算,原 Turn/events 不改写。
上游 EOF 与业务本身正确性仍由原执行 owner 处理;本 PR 不重做业务、不启动新模型,也不把答复恢复当作新执行。正常采用和自然生产投递另行读回。
Validation
fe82148778be76b6956169e6652208943711fb36;最终源码/fixture 与通过检查时哈希一致。559cb354fc4f8670f26e88dee38136c42757735a为5 failed /15 passed,最终 head 为20 passed;pytest -q tests/test_steward_interrupted_answer.py -k missing_final_message。pytest -q tests/test_antigravity_steward_adapter.py tests/test_chat_response_parsing.py:192 passed;最终前后源码哈希一致。e79e47d625146c1e8f96d5ae35fdd51be1a00059完全不变,复用其相关 owner 检查;该次整体试跑619 passed、3项共享解析器回归失败,后者通过恢复原解析契约及最终192+20项检查解决,不冒称旧试跑全绿。审查中发现全局 missing-message 前缀复用违反既有契约,已撤回通用解析器变更;一次流过滤方案又暴露重复路径脱敏,已改用共享 envelope locator 和单次原 redactor,最终测试没有放宽断言。较早试跑/失败均保留,不作为最终资格。模块增长检查曾失败,现将结果选择与 receipt 收回 Core,私聊文件2189行,低于既有2191上限,未提高上限。按当前策略未查询、轮询或等待 CI。
Frontend / Visual Evidence
Type of Change
LoopX Area
Shared-authority RFC fixture impact
N/A;没有 storage-authority、runtime-routing 或 provider-promotion 变更。
Boundary Checklist