From 0169823b7291b89f620a45adeb7a415a94f65ac2 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sat, 13 Jun 2026 09:22:32 +0800 Subject: [PATCH] =?UTF-8?q?chore(docs):=20=E5=90=88=E5=B9=B6=20mail-failur?= =?UTF-8?q?e-notification=20=E5=88=B0=20=C2=A720=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=AE=BE=E8=AE=A1=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mail-failure-notification.md → archive-3.0/ - §20 新增 §20 Mail 失败通知机制(v2.0 AI Native) - 失败场景与重试耗时完整表 - reason 人话翻译映射 - 通知模板增强(detail 传入 + 重试情况) - api_error rate_limit 待改为可恢复 retry - §18→§21,§19→§22 编号顺延 --- docs/design/20-task-type-architecture.md | 148 +++++++++++++++++- .../mail-failure-notification.md | 0 2 files changed, 146 insertions(+), 2 deletions(-) rename docs/design/{ => archive-3.0}/mail-failure-notification.md (100%) diff --git a/docs/design/20-task-type-architecture.md b/docs/design/20-task-type-architecture.md index e5cd414..0a1dd04 100644 --- a/docs/design/20-task-type-architecture.md +++ b/docs/design/20-task-type-architecture.md @@ -950,7 +950,151 @@ handler.post_complete(task_id, agent_id, outcome, db_path) --- -# §18 设计决策记录 +## §20. Mail 失败通知机制 + +### 20.1 背景 + +Mail 是 A→B 点对点通信,失败应通知发件人 A,而非统一 @pangtong。 + +当前机制(v1.3 已实现): +- `_mark_task("failed")` 对 _mail 项目:调用 `mail_notify.notify_mail_failed` 通知发件人 +- `_mark_task("failed")` 对 Task 项目:@pangtong-fujunshi(F2 原逻辑不变) +- `_mail_auto_complete` 的 no_reply_found:标 failed 后通知发件人 +- 防递归:`must_haves.system_notify=true` 的邮件失败不再递归通知 + +### 20.2 失败场景与重试机制 + +所有可能的失败路径及其重试/等待机制(重试上限 max_retries=3,agent_timeout=630s): + +| 失败类型 | 机制 | 重试次数 | 每次耗时 | cooldown | 最长总耗时 | +|---|---|---|---|---|---| +| `gateway_timeout` | 续杯 | 3 | 630s | 无 | ~31.5 分钟 | +| `crashed` | ticker 兜底 | 3 | ~2-5 分钟 | 60s + 30s ticker | ~15 分钟 | +| `api_error`(rate_limit) | 推 pending(**待改为续杯**) | 3 | ~2.5 分钟 | 120s | ~8 分钟 | +| `compact_interrupted` | 续杯 | 3 | 630s | 60s | ~34 分钟 | +| `gateway_unreachable` | 续杯 | 3 | 630s | 60s | ~34 分钟 | +| `lock_conflict` | 续杯 | 3 | 630s | 60s | ~34 分钟 | +| `fallback_timeout` | 续杯(A3b) | 3 | 630s | 60s | ~34 分钟 | +| `compact_wait` | monitor 等待 | 3 | 630s | 无 | ~31.5 分钟 | +| `compact_hanging` | monitor → release | 3 | 630s | 300s | ~31.5 分钟 + ticker | +| `max_monitor_timeouts` | monitor 上限 | 3 | 630s | 无 | ~31.5 分钟 | +| `session_stuck` | revive 1 次 | 1 | ~30s | 无 | ~30 秒 | +| `compact_failed` | 无重试 | 0 | — | 300s | 立刻 failed | +| `auth_failed` | 无重试 | 0 | — | — | 立刻 failed | +| `agent_error` | 无重试 | 0 | — | 300s | 立刻 failed | +| `no_reply_found` | 无重试 | 0 | — | — | 立刻 failed | + +### 20.3 触发点 + +| 触发点 | 文件 | 说明 | +|---|---|---| +| `_mark_task(failed)` | spawner.py | _mail 项目 → notify_mail_failed;Task 项目 → @pangtong | +| `_mail_auto_complete` no_reply_found | dispatcher.py | Agent 正常退出但没回复 request → 标 failed → 通知发件人 | + +### 20.4 实现位置 + +- `src/daemon/mail_notify.py`:`notify_mail_failed` + `_is_mail_project` + 通知模板 +- `src/daemon/spawner.py`:`_mark_task` 中 _mail/Task 分流 +- `src/daemon/dispatcher.py`:`_mail_auto_complete` 中 no_reply_found 后调 notify + +### 20.5 通知设计(v2.0 — AI Native) + +通知提供充足事实信息,不做硬编码处理建议。收件 AI 自行判断下一步。 + +**通知结构**: +``` +邮件投递失败通知 + +📧 原始邮件:「{title}」 +👤 收件人:{to_agent} +❌ 失败原因:{reason_human_readable}({reason_raw}) +📊 重试情况:{attempt_info} +📋 上下文信息: +{detail_formatted} + +常见失败原因参考: +• no_reply_found:收件人未回复(Agent 未能识别或处理此邮件) +• crashed / max_crash_count:收件人处理时进程崩溃(已自动重试 3 次) +• max_retries:续杯耗尽(已自动重试 3 次,共约 34 分钟) +• max_api_retry_count:API 连续失败达上限(rate_limit/500/503) +• max_monitor_timeouts:处理超时达上限(共约 31.5 分钟) +• gateway_timeout:Agent 执行超时(已续杯重试) +• session_stuck:Agent 会话假死(lock PID 死亡,revive 失败) +• revive_failed:会话假死后恢复失败 +• auth_failed:Agent 认证失败(配置问题) +• fallback_exhausted:主模型和备用模型均失败 +• agent_failed:收件人主动标记失败 +• compact_failed:上下文压缩失败 +• compact_hanging:上下文压缩长时间未完成(等待超 31.5 分钟) +• compact_interrupted:上下文压缩被中断(已自动重试 3 次) +• gateway_unreachable:Gateway 不可达(已自动重试 3 次) +• lock_conflict:会话锁冲突(已自动重试 3 次) +• 其他:建议排查系统日志 + +——系统自动通知 +``` + +**reason 人话翻译映射**: + +| reason_raw | reason_human_readable | detail 提取 | +|---|---|---| +| `no_reply_found` | 收件人未回复 | 无额外信息 | +| `crashed` | 处理时进程崩溃 | stderr_preview 前 200 字 | +| `max_crash_count` | 连续崩溃达上限 | count + stderr_preview | +| `max_retries` | 续杯耗尽 | count + retry_field | +| `max_api_retry_count` | API 连续失败达上限 | count | +| `max_monitor_timeouts` | 处理超时达上限 | count + elapsed_seconds | +| `gateway_timeout` | Agent 执行超时 | retry_count | +| `session_stuck` | 会话假死 | stuck_count | +| `revive_failed` | 假死后恢复失败 | stuck_count | +| `auth_failed` | 认证失败 | stderr_preview | +| `fallback_exhausted` | 模型全部失败 | fallback_count + fallback_reason | +| `agent_failed` | 收件人主动标失败 | 无 | +| `compact_failed` | 上下文压缩失败 | stderr_preview | +| `compact_hanging` | 压缩长时间未完成 | compact_wait_count | +| `compact_interrupted` | 压缩被中断 | 无 | +| `gateway_unreachable` | Gateway 不可达 | stderr_preview | +| `lock_conflict` | 会话锁冲突 | 无 | +| 默认 | 未知原因 | reason + stderr_preview(如有) | + +**重试情况格式**: +- 有重试:`"已自动重试 {count} 次,共耗时约 {total_time}"` +- 无重试:`"无法重试({reason_human_readable})"` + +### 20.6 防递归 + +系统通知邮件(from=system)本身也可能失败: +- 检查 `must_haves.system_notify=true` → 跳过递归通知 +- system 不是有效 Agent → 通知路由到 pangtong-fujunshi 代处理 + +### 20.7 待实现改动 + +#### P1:api_error rate_limit 改为可恢复 retry + +**当前**:`_classify_outcome` 中 rate_limit/500/503 → `api_error`,`should_retry=False`,走推 pending 路径。 +**改为**:`should_retry=True`,走续杯路径。cooldown 60s。上限仍 3 次。 +**改动文件**:`src/daemon/spawner.py` `_classify_outcome` 的 `api_error` 分支。 +**影响**:`api_retry_count` 机制可以废弃(统一用 `retry_count`),但保持向后兼容暂不删除。 + +#### P2:通知模板更新(v2.0) + +**当前**:`mail_notify.py` 的 `_NOTIFY_TEMPLATE` 是静态模板,不传 detail。 +**改为**:动态模板,根据 reason 选择人话翻译 + 提取 detail 信息 + 格式化重试情况。 +**改动文件**:`src/daemon/mail_notify.py`。 +**新增**:`_REASON_MAP` 字典(reason → 人话 + detail 提取函数)。 + +### 20.8 不改的 + +| 项目 | 原因 | +|---|---| +| F2 @pangtong 对 Task 的逻辑 | Task failed 仍 @pangtong,只对 Mail 不同 | +| no_reply_found 的判定逻辑 | 只在判定后加通知,不改判定本身 | +| inform 类型邮件的完成逻辑 | inform 直接 done,不存在 no_reply_found | +| 外部 API 的 from 校验 | system 不走 HTTP,外部无法伪造 | + +--- + +# §21 设计决策记录 本节记录设计过程中的关键讨论和决策,便于未来回顾。 @@ -1010,7 +1154,7 @@ handler.post_complete(task_id, agent_id, outcome, db_path) --- -## §19. 审查与验证历史 +## §22. 审查与验证历史 ### Step 2-5 背靠背审查(2026-06-10/11) diff --git a/docs/design/mail-failure-notification.md b/docs/design/archive-3.0/mail-failure-notification.md similarity index 100% rename from docs/design/mail-failure-notification.md rename to docs/design/archive-3.0/mail-failure-notification.md -- 2.45.4