fix(lark): return timed-out private conversation results - #5607
Conversation
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 | model=gpt-6.1-sol | provider=OpenAI | reasoning_effort=xhigh | declaration_source=runtime_reported | observation=98b47db0742b44f7bbc50fdc19057b889f0d2fb100d3787fbbd3e617a78de3d4
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Exact reviewed head: 5607@c1ff443feb6c89982c9007dab6dcbf0383c2a0e0. Immutable base: 37b77d4aff1e1e9faa14487888c055c99482c43e.
动机
使用已配置 Bot 私聊的普通项目用户,以及明确确认新委托的管家用户。
用户在已授权的 Bot 私聊发起耗时工作。Core 已将原 Turn 记为 timed_out,旧适配器仍等待终态,原消息得不到结果;本修复在原私聊告知超时并保留状态和恢复命令,发送凭据未验证时只继续核验。
普通 idle/hard 超时与注入的委托首轮超时均返回原消息;重启和事件重投没有新模型请求或重复发送,超时事实不伪改为成功。
不新增授权、Goal 调度或生命周期;真实外部账户、安装版切换和真实委托 deadline 的资格仍留在既有 switch gate。
这是一项 justified_increment:解决当前适配器漏掉原生超时终态的具体问题;剩余缺口是安装版真实 provider 恢复和真实委托 deadline,由既有文档的切换验收继续承担,不能用本评审替代它。
改动思路
现有 Chat/Core 已经持久保存 Session、Turn 和终态,Lark 适配器应呈现它们。PR 删除两个独立终态集合,直接使用既有 TERMINAL_TURN_STATES,分别处理普通回复和已确认委托的首轮结果;原消息发送、凭据保存、回读、ACK 和恢复继续使用 _deliver 及既有 Inbox。Python 代码留在 bundled Lark provider 合理,这里只翻译 provider 的输入输出,没有新增通用决策源、权限或调度器。
不修会继续在超时后长期 pending;只修普通回复会遗留委托路径;增加自动重试模型会破坏既有不重放契约。当前同一 owner 的小修复比新增恢复机制更合适。
具体改动
整个 diff 是三文件 +113/-4:provider +7/-4、readiness 文档 +9,以及一个 97 行原生回归文件。没有新配置、CLI、receipt schema 或存储状态。文档明确合成 host/provider 的证据范围,并保留实际安装切换门。
关键代码讲解
loopx/extensions/lark/private_conversations.py:264:普通分支读取原 Session/Turn;缺失或非终态继续等待,timed_out现在进入原消息结果发送并给出/status,不会改成 completed。loopx/extensions/lark/private_conversations.py:278:委托首轮也用同一终态 owner;超时文本保留原 Goal、resource ids 和/resume-commission,没有另造执行或 Goal。loopx/extensions/lark/private_conversations.py:195:复用未改的_deliver。首次尝试先保存 started/locator;重启后 verify 同一个 attempt,未经验证不能 ACK,原消息与现有 binding 仍须重新校验。
规范依据:loopx/extensions/lark/docs/realtime-conversation-readiness.md,spec_revision=37b77d4aff1e1e9faa14487888c055c99482c43e,使用 PR 前的不可变文本判断,而不是新增文案自证。terminal-canonical-result 已实现(原 timed_out 保留);delivery-only-recovery 已实现(不可见回执仅恢复验证);original-source-and-session 已实现(原消息/受众/会话验证);installed-provider-switch 明确 deferred,由既有切换 owner 运行安装版真实账户/宿主旅程。
语义与 CI 对齐
这次 reuse_existing:原生终态 owner 是 completed/interrupted/timed_out/failed;旧适配器中的 expired 没有合法 producer,原生队列过期本来就保存为 timed_out/session_queue_expired。开发期 advisory 没发现支持的新词汇 carrier,全树 semantic smoke 通过;空 advisory 不代表完整语义证明。按本次策略未查询或等待 CI。
对主干的风险
最危险的反例是执行已超时后原消息受众或授权发生变化,以及回复已经发送但 provider 暂时无法读回。独立实际 Core/Inbox 测试验证:改原消息 chat id 或撤销 binding 后零发送;重新创建 binding 不接管旧请求;恢复同一个合法原消息后只验证已存 attempt。重启和 event_id 改变的重投没有第二次发送、第二个模型请求或新的 Session。原失败状态始终保留。
当前 head 22 项相关测试和 16 项状态/Agent companion 测试通过;隔离矩阵六项通过(含三项 deadline/commission 和三项独立 source/authority/ordinary control)。同一隔离 deadline 矩阵在 immutable base 的三项都因缺少超时结果失败;ordinary completed control 在 base/head 的完整归一化结果 SHA256 都是 dc6d9f3b57dba0bcabe779165edb920040d0b2f3080a980463d570d75740ae65。委托 case 在启动后注入 typed host timeout,不能证明真实 Goal deadline。
早期放在外部证据目录的探针没有加载 tests/conftest 的默认 runtime 隔离,因此委托停在准备阶段;另两处把内部 reconcile 计数和重建 binding id 当不变条件也是错误测试预期。已保留失败记录并补上原隔离 fixture,改验真正的发送次数、原资源、授权和模型请求,不把早期 setup 错误称为产品缺陷。
Canonical mypy19、Ruff、全树 semantic、diff/public-boundary 和 native exact-diff premerge 通过。五个 direct 检查通过;11 个 selected 执行,十个通过、一个 inherited maintainability advisory 仍失败:同 base/head 都是 module_metric_budget:loopx/extensions/lark/goal_topic_runtime.py,因果文件 blob 相同且 magnitude regression=0;保留该债务,不能宣称每个检查全绿。原生 change-quality 的严格 receipt 同样保留 fail / validator:inherited_ratchet;该独立合并资格失败不被本 APPROVE 覆盖。
先前 main 525bfa26f3e8c8981c7f6c65f06d1f6426d38297 的纯 merge tree 六项通过;收到相邻 #5634 实际合并的消息后,重新拉取 main 59eb5d5976663c1ea52d31d1a7299c1dda39595e,对其纯 merge tree c322b923bfdc0a3d3e4da8165e07c0612ba6ea52 再执行同一六项隔离探针,仍全部通过。两组组合不是已发布 commit 或安装版本。没有验证真实外部账户、产品切换、长期时延,也没有修改活跃配置/凭据。
我的整体评价
APPROVE。long_horizon 和 user_experience 都是 improved:原先终态仍无结果,现在可收到明确失败并用原会话继续恢复,发送验证不会引入重复工作。bounded future-facing pass 已应用:删除两个复制的终态规则;把普通/委托展示强行再抽成泛用层没有必要。完整生产增量仅七行新增,规范/验证与其直接相关,比例合适。
该结论只接受这项源代码修复;安装版 switch gate、真实 provider 恢复和真实委托 deadline 尚未验收,仍由现有维护者/发布流程处理。运行时 PR 交维护者整合;COMMENTED 是 GitHub 同账号限制下的完整批准结论,不是平台 formal APPROVED,也不赋予合并权限。
English verdict: APPROVE - 5607@c1ff443feb6c89982c9007dab6dcbf0383c2a0e0. Reuse the canonical terminal owner to return ordinary and commission timeout failures through the original source, with saved-attempt recovery and no resend/model replay. Source-level native/negative/base-head checks pass; live installed provider/deadline qualification and the inherited unrelated module advisory remain explicit.
When a native private Turn times out, Core records
timed_outbut the Lark adapter leaves its result pending indefinitely. Ordinary replies and commission first-round results now use the existing Chat terminal-state owner and return an actionable timeout message in the original conversation. Provider readback continues to gate delivery; restart/redelivery reconcile the saved attempt without another model execution or send.Placement: this is a bundled Lark transport correction within native-chat. The bounded refactor removes two copied terminal classifications; it adds no state owner, scheduler, permission, or runner. Readiness remains tied to the existing real-time conversation/RFC acceptance, with live-provider recovery required at the switch gate.
Validation:
goal_topic_runtime.py(outside this diff).Runtime change: proposed for maintainer review/merge; no self-merge or admin bypass.