From 89a4784c1067143d34441d7c426971dbbda35ebd Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 7 Sep 2026 07:05:45 +0800 Subject: [PATCH] =?UTF-8?q?opencode+dsh:=20=E7=A9=BA=E5=9B=9E=E5=A4=8D?= =?UTF-8?q?=E5=85=9C=E5=BA=95=20=E2=80=94=E2=80=94=20idle=20=E4=BD=86?= =?UTF-8?q?=E6=97=A0=20assistant=20=E6=96=87=E6=9C=AC=E6=97=B6=E5=9B=9E?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 缺口:模型 idle(轮次正常结束)但没有产出任何 assistant 文本时, 两个插件此前静默 return —— 发件人等不到任何回复也得不到交代。 (模型「全部失败」已有 renderFailureReport 兜底,但「跑完却没产出」 不等于失败,走不到那条。) 补: - opencode relaySummary: if (!last) → 发一封「处理失败:无回复文本」通知 - dsh agent/status idle: if (!lastText) → 同款通知 - 都走 relay:summary 免配额 + relay_key 幂等 - 都只给人类来信发(Agent 间不自动转发) --- plugins/dsh-mail-bridge/src/index.ts | 26 +++++++++++++++++++++++++- plugins/opencode-mail-bridge/index.js | 27 ++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/plugins/dsh-mail-bridge/src/index.ts b/plugins/dsh-mail-bridge/src/index.ts index 4bed0d7..a81c579 100644 --- a/plugins/dsh-mail-bridge/src/index.ts +++ b/plugins/dsh-mail-bridge/src/index.ts @@ -1536,7 +1536,31 @@ export function apply(ctx: any, config: PluginConfig): void { // 取最后一条 assistant 消息的文本 const events = agent.session?.events ?? []; const lastText = lastAssistantText(events); - if (!lastText) return; + if (!lastText) { + // 模型 idle 但没有任何 assistant 文本:空回复/被中断在文本前。 + // 此前静默返回 —— 发件人等不到任何回复(缺的是 B-6 的「模型全部失败」 + // 同款兜底,只是这次没有失败可报却也没有产出)。给发件人一封失败通知。 + // 只给人类来信发:Agent 之间不自动转发(与上面同一判据)。 + try { + await client.post('/mail/send', { + to: mctx.replyTo, + subject: `处理失败: ${mctx.subject || '(无主题)'}`, + body: [ + `这封邮件(主题:${mctx.subject || '(无主题)'})的处理轮次已结束,但没有产出任何回复文本。`, + '', + '可能原因:模型空响应、输出被中断、或工具调用异常耗尽轮次。', + '请检查后重试。', + ].join('\n'), + reply_to: mctx.mailID || '', + relay: 'summary', + relay_key: clampRelayKey(`empty-reply:${mailSessionID}`), + }); + console.error(`[dsh-mail-bridge] 已发空回复失败通知给 ${mctx.replyTo}`); + } catch (e: any) { + console.error(`[dsh-mail-bridge] 空回复失败通知也发不出去: ${e?.message || e}`); + } + return; + } // 本轮模型已亲手回过这条线索 → 不再自动转发(与 opencode 侧同一取舍) if (shouldSkipAutoRelay(explicitSends.get(String(agent.id)), mctx.replyTo, mctx.mailID)) { diff --git a/plugins/opencode-mail-bridge/index.js b/plugins/opencode-mail-bridge/index.js index cf33a09..28c0a9f 100644 --- a/plugins/opencode-mail-bridge/index.js +++ b/plugins/opencode-mail-bridge/index.js @@ -762,7 +762,32 @@ async function relaySummary(client, directory, sessionID) { if (text) { last = { id: m.info.id, text }; } break; } - if (!last) return null; + if (!last) { + // 模型 idle 但没有任何完成的 assistant 文本:空回复或被中断在文本前。 + // 此前静默返回 —— 发件人等不到任何回复(B-6 的缺口:跳过了 + // 「模型全部失败」那条兜底,因为没有失败可报,却也没有产出)。 + // 给发件人一封失败通知,让他知道这封已经处理过了但没结果。 + try { + await apiPost("/mail/send", { + to: ctx?.replyTo || "", + subject: `处理失败: ${ctx?.subject || "(无主题)"}`, + body: [ + `这封邮件(主题:${ctx?.subject || "(无主题)"})的处理轮次已结束,但没有产出任何回复文本。`, + "", + "可能原因:模型空响应、输出被中断、或工具调用异常耗尽轮次。", + "请检查后重试。", + ].join("\n"), + reply_to: ctx?.mailID || "", + relay: "summary", + relay_key: clampRelayKey(`empty-reply:${mailSessionID || sessionID}`), + }); + console.error(`[mail-bridge] 已发空回复失败通知给 ${ctx?.replyTo || ""}`); + } catch (e) { + // 失败通知也发不出去就静默:这次至少试过了 + console.error("[mail-bridge] 空回复失败通知也发不出去:", e?.message || e); + } + return null; + } // 本地去重(服务端另有 relay_key 幂等兜底,这里只是少打一次网关) if (relayedSummaries.get(sessionID) === last.id) return null;