Files
sanguo_moziplus_v2/src/daemon/mail_notify.py
T
cfdaily d58e38d58f
CI / lint (pull_request) Successful in 6s
CI / test (pull_request) Successful in 9s
CI / notify-on-failure (pull_request) Successful in 0s
fix(lint): 修复 PR #14 引入的 lint 回退 (119→0)
PR #14 从旧分支复制文件导致回退了 PR #10 的 lint 修复。
修复内容:
- autoflake 移除未使用导入/变量
- autopep8 修复缩进/空格
- 手动修复 F821(pathlib→Path), F541(f-string), F841(未使用变量)
- 所有修复均通过 flake8 --max-line-length=120 --extend-ignore=E501 检查 (0 errors)
2026-06-09 23:53:29 +08:00

124 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Mail 失败通知 — 以 system 身份通知发件人"""
from __future__ import annotations
import json
import logging
from datetime import datetime
from pathlib import Path
from typing import Optional
from src.blackboard.models import Task
from src.blackboard.operations import Blackboard
from src.config.agents import AGENT_IDS
logger = logging.getLogger(__name__)
# 邮件通知正文模板(统一模板,包含所有可能的失败原因和建议)
_NOTIFY_TEMPLATE = """你的邮件投递失败了。
📧 原始邮件:「{title}
👤 收件人:{to_agent}
❌ 失败原因:{reason}
常见失败原因及处理建议:
• no_reply_found:收件人未回复。建议重发邮件,或通过黑板任务方式联系
• auth_failed:收件人认证失败。需检查 Agent 配置,联系姜维(jiangwei-infra)排查
• crash_limit:收件人处理时多次崩溃。系统异常,建议稍后重试
• task_timeout:处理超时。建议重发或通过其他方式联系
• 其他原因:建议联系副军师(pangtong-fujunshi)排查
——系统自动通知"""
def _is_mail_project(db_path: Path) -> bool:
"""从 db_path 推断是否为 _mail 项目"""
path_str = str(db_path)
return "/_mail/" in path_str or path_str.endswith("_mail.db")
def notify_mail_failed(db_path: Path, original_mail_id: str,
reason: str, detail: Optional[dict] = None) -> None:
"""Mail 失败后以 system 身份给发件人发通知邮件
直接通过 Blackboard 创建 Task,不走 HTTP API。
防递归:检查原邮件 must_hives.system_notify,为 true 则跳过。
发件人不是有效 Agent(如 system)→ 通知庞统代处理,避免广播风暴。
"""
try:
bb = Blackboard(db_path)
original = bb.get_task(original_mail_id)
if not original:
logger.warning(
"notify_mail_failed: original mail %s not found",
original_mail_id)
return
# 解析原邮件元数据
meta = json.loads(original.must_haves) if original.must_haves else {}
# 防递归:系统通知邮件失败不再发通知
if meta.get("system_notify"):
logger.info(
"Mail %s: system notify mail failed, skipping recursive notification",
original_mail_id)
return
# 获取发件人(优先 assigned_byfallback must_haves.from
from_agent = original.assigned_by or meta.get("from", "")
to_agent = original.assignee or ""
title = original.title or ""
if not from_agent:
logger.warning(
"notify_mail_failed: cannot determine sender for mail %s",
original_mail_id)
return
# 发件人不是有效 Agent(如 system)→ 通知庞统代处理,不触发广播
target_agent = from_agent
if from_agent not in AGENT_IDS:
logger.warning("Mail %s: sender '%s' is not a valid agent, routing failure notice to pangtong-fujunshi",
original_mail_id, from_agent)
target_agent = "pangtong-fujunshi"
# 构造通知正文
text = _NOTIFY_TEMPLATE.format(
title=title,
to_agent=to_agent,
reason=reason,
)
# 创建通知邮件 Task
notify_id = f"mail-{int(datetime.now().timestamp() * 1000)}"
notify_meta = {
"type": "inform",
"performative": "inform",
"is_read": False,
"conversation_id": meta.get("conversation_id", ""),
"in_reply_to": original_mail_id,
"from": "system",
"system_notify": True,
}
notify_task = Task(
id=notify_id,
title=f"[投递失败] {title}",
description=text,
assignee=target_agent,
assigned_by="system",
must_haves=json.dumps(notify_meta, ensure_ascii=False),
task_type="mail",
status="pending",
)
bb.create_task(notify_task)
logger.info("Mail %s: sent failure notification to %s (original_sender=%s, reason=%s, notify_id=%s)",
original_mail_id, target_agent, from_agent, reason, notify_id)
except Exception as e:
logger.warning(
"notify_mail_failed: failed to send notification for mail %s: %s",
original_mail_id,
e)