Files
MailUI4Agents/plugins/dsh-mail-bridge
JianFeeeee 24f7ed99fc fix(dsh)★★: idle 时取不到 assistant 文本 —— 重试而非当场判「空回复」
## 用户报「dsh 插件还是没有正确回复邮件」

第一版修复(519bdf7)改对了 `lastAssistantText` 本身,但生产仍复现。取证后定位
到**第二层原因**:不是取错事件,而是**取的时候那条还没到**。

## 证据(生产 22:56 那次,磁盘 session.v4.jsonl.zstd 解压)

那一轮的事件是:

    seq=50 step/start
    seq=51 assistant/message  块=['text']   ← 模型确实写了完整文本
    seq=52 step/end   seq=53 turn/end

按修复后的逻辑(从后往前找第一条带 text 的 assistant)**必然会取到 seq=51**,
可它仍被判成空回复。

⇒ 唯一解释:`agent/status: idle` 触发的那一刻,`agent.session.events` 里
**还没有 seq=51** —— 宿主在最后一条 assistant 消息落入内存**之前**就发了 idle。

旁证:投影缓存 `/root/.dsh/storages/session_projcache/sessions/<id>.json`
只有 `{identity, rows}`,**没有 events** ⇒ 它不是从投影读的,确属内存对象。

## 修法:idle 时取不到就短暂重试

重试 3 次 × 250ms(合计 750ms)。远小于一轮模型思考的量级,不拖慢链路;
而 seq=51 落盘只需几毫秒,三次足够覆盖。

顺带把诊断日志改成打出**重试后**的 events 长度与末尾类型(附「第 N 次重试才拿到」)
——下一次复现就能直接验证这个推断是否成立,而不是再靠推测。

## 一条被推翻的推断(记下来)

我一度判定「根因是 resume 路径」,理由是新会话那次通过、resume 那次失败。
**这是错的**:那两次的差异其实在更早一步 ——
`shouldSkipAutoRelay`(模型已主动 send_mail 就早退)。C-1 新会话与 C-2 resume
都因为 dsh 主动回信而早退,压根没走到取文本那段,所以两者都「正常」。
⇒ resume 与本问题**无关**,此前把差异归因于它是观察不足。

## 一条设定更正(用户指出)

我曾说「Agent 间通信不自动转发」是不可协商的约定,并据此说「pi 发信会早退,
拿不到诊断日志」。用户更正:agent→agent 只是**消耗额度**,而额度会随时间恢复
——那是成本权衡,不是禁止。该约定来自 784192d(2026-09-04),四个桥共用同一份
relay-policy.js,它**没有随额度恢复机制一起更新**。

⚠ 该约定是否要改属成本策略,未擅自改动。但它确实挡在诊断路径前面,是本轮
多花一轮的直接原因。

## 验证状态(诚实标注)

- tsc 零错 · dsh 435 格全绿 · 部署成功(current → 20261004-073447)
- **最终行为验证未完成**:需要一次**真人发信**(`from_human=true`)才能走到
  取文本那段。我的所有身份都是 Agent,会被「不自动转发」早退。
  ⇒ 诊断日志已就位,待真人复现时可直接读出 events 的真实内容。
2026-10-04 07:35:23 +08:00
..