Files
X-Agents/agent/app/core/tools/impl/notify.py
2026-03-11 14:26:53 +08:00

380 lines
9.5 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.
"""
通知工具
提供发送通知的功能邮件、Webhook等
"""
import httpx
from typing import Dict, Any, Optional, List
from dataclasses import dataclass
from enum import Enum
class NotificationType(Enum):
"""通知类型"""
EMAIL = "email"
WEBHOOK = "webhook"
SMS = "sms"
DINGTALK = "dingtalk"
WECHAT = "wechat"
SLACK = "slack"
@dataclass
class NotificationConfig:
"""通知配置"""
# Email配置
smtp_host: str = ""
smtp_port: int = 587
smtp_user: str = ""
smtp_password: str = ""
from_email: str = ""
# Webhook配置
webhook_url: str = ""
webhook_secret: str = ""
# 钉钉配置
dingtalk_webhook: str = ""
# Slack配置
slack_webhook: str = ""
class NotificationTool:
"""
通知工具
支持多种通知渠道:
- Email (SMTP)
- Webhook
- 钉钉
- Slack
"""
def __init__(self, config: Optional[NotificationConfig] = None):
self.config = config or NotificationConfig()
async def send_email(
self,
to: str,
subject: str,
body: str,
cc: Optional[List[str]] = None,
is_html: bool = False
) -> Dict[str, Any]:
"""
发送邮件
Args:
to: 收件人
subject: 主题
body: 内容
cc: 抄送列表
is_html: 是否HTML格式
Returns:
发送结果
"""
if not self.config.smtp_host:
return {
"success": False,
"error": "Email not configured"
}
try:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 构建邮件
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = self.config.from_email or self.config.smtp_user
msg['To'] = to
if cc:
msg['Cc'] = ",".join(cc)
# 添加内容
content_type = "html" if is_html else "plain"
msg.attach(MIMEText(body, content_type))
# 发送
with smtplib.SMTP(self.config.smtp_host, self.config.smtp_port) as server:
server.starttls()
server.login(self.config.smtp_user, self.config.smtp_password)
server.send_message(msg)
return {
"success": True,
"type": "email",
"to": to,
"subject": subject
}
except Exception as e:
return {
"success": False,
"error": str(e),
"type": "email"
}
async def send_webhook(
self,
url: str,
data: Dict[str, Any],
method: str = "POST",
headers: Optional[Dict[str, str]] = None
) -> Dict[str, Any]:
"""
发送Webhook
Args:
url: Webhook URL
data: 请求数据
method: HTTP方法
headers: 请求头
Returns:
发送结果
"""
try:
async with httpx.AsyncClient(timeout=10) as client:
response = await client.request(
method=method,
url=url,
json=data,
headers=headers
)
return {
"success": response.status_code < 400,
"status_code": response.status_code,
"type": "webhook",
"url": url
}
except Exception as e:
return {
"success": False,
"error": str(e),
"type": "webhook"
}
async def send_dingtalk(
self,
message: str,
webhook: Optional[str] = None
) -> Dict[str, Any]:
"""
发送钉钉消息
Args:
message: 消息内容
webhook: 自定义webhook URL
Returns:
发送结果
"""
url = webhook or self.config.dingtalk_webhook
if not url:
return {
"success": False,
"error": "Dingtalk webhook not configured"
}
try:
async with httpx.AsyncClient(timeout=10) as client:
response = await client.post(
url,
json={
"msgtype": "text",
"text": {
"content": message
}
}
)
result = response.json()
return {
"success": result.get("errcode") == 0,
"type": "dingtalk",
"response": result
}
except Exception as e:
return {
"success": False,
"error": str(e),
"type": "dingtalk"
}
async def send_slack(
self,
message: str,
channel: Optional[str] = None,
webhook: Optional[str] = None
) -> Dict[str, Any]:
"""
发送Slack消息
Args:
message: 消息内容
channel: 频道
webhook: 自定义webhook URL
Returns:
发送结果
"""
url = webhook or self.config.slack_webhook
if not url:
return {
"success": False,
"error": "Slack webhook not configured"
}
try:
payload = {"text": message}
if channel:
payload["channel"] = channel
async with httpx.AsyncClient(timeout=10) as client:
response = await client.post(url, json=payload)
return {
"success": response.status_code == 200,
"type": "slack",
"status_code": response.status_code
}
except Exception as e:
return {
"success": False,
"error": str(e),
"type": "slack"
}
async def send(
self,
type: str,
message: str,
**kwargs
) -> Dict[str, Any]:
"""
统一发送接口
Args:
type: 通知类型 (email, webhook, dingtalk, slack)
message: 消息内容
**kwargs: 其他参数
Returns:
发送结果
"""
type = type.lower()
if type == "email":
return await self.send_email(
to=kwargs.get("to", ""),
subject=kwargs.get("subject", "Notification"),
body=message,
cc=kwargs.get("cc")
)
elif type == "webhook":
return await self.send_webhook(
url=kwargs.get("url", ""),
data=kwargs.get("data", {"message": message})
)
elif type == "dingtalk":
return await self.send_dingtalk(
message=message,
webhook=kwargs.get("webhook")
)
elif type == "slack":
return await self.send_slack(
message=message,
channel=kwargs.get("channel"),
webhook=kwargs.get("webhook")
)
else:
return {
"success": False,
"error": f"Unknown notification type: {type}"
}
# 全局通知工具
notification_tool = NotificationTool()
# 便捷函数
async def send_notification(
type: str,
message: str,
**kwargs
) -> Dict[str, Any]:
"""发送通知"""
return await notification_tool.send(type, message, **kwargs)
async def send_email(
to: str,
subject: str,
body: str
) -> Dict[str, Any]:
"""发送邮件"""
return await notification_tool.send_email(to, subject, body)
async def send_webhook(
url: str,
data: Dict[str, Any]
) -> Dict[str, Any]:
"""发送Webhook"""
return await notification_tool.send_webhook(url, data)
# 工具定义
SEND_NOTIFICATION_TOOL = {
"name": "send_notification",
"description": "Send notifications via email, webhook, dingtalk, or slack.",
"parameters": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "Notification type: email, webhook, dingtalk, slack",
"enum": ["email", "webhook", "dingtalk", "slack"]
},
"message": {
"type": "string",
"description": "The notification message"
},
"to": {
"type": "string",
"description": "For email: recipient email address"
},
"subject": {
"type": "string",
"description": "For email: email subject"
},
"url": {
"type": "string",
"description": "For webhook: webhook URL"
},
"data": {
"type": "object",
"description": "For webhook: JSON data to send"
},
"webhook": {
"type": "string",
"description": "Custom webhook URL for dingtalk/slack"
},
"channel": {
"type": "string",
"description": "For slack: channel name"
}
},
"required": ["type", "message"]
}
}