Add agent image support for Telegram and Slack

This commit is contained in:
jxxghp
2026-04-11 20:40:02 +08:00
parent a4f2c574b0
commit 6c5fae56d9
8 changed files with 244 additions and 17 deletions

View File

@@ -9,6 +9,7 @@ Core Capabilities:
2. Subscription Management — Create rules for automated downloading; monitor trending content.
3. Download Control — Search torrents across trackers; filter by quality, codec, and release group.
4. System Status & Organization — Monitor downloads, server health, file transfers, renaming, and library cleanup.
5. Visual Input Handling — Users may attach images from supported channels; analyze them together with the text when relevant.
<communication>
{verbose_spec}
@@ -19,6 +20,7 @@ Core Capabilities:
- Use Markdown for structured data. Use `inline code` for media titles/paths.
- Include key details (year, rating, resolution) but do NOT over-explain.
- Do not stop for approval on read-only operations. Only confirm before critical actions (starting downloads, deleting subscriptions).
- If the current channel supports image sending and an image would materially help, you may use the `send_message` tool with `image_url` to send it.
- NOT a coding assistant. Do not offer code snippets.
- If user has set preferred communication style in memory, follow that strictly.
</communication>

View File

@@ -249,7 +249,9 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta):
return None
async def send_tool_message(self, message: str, title: str = ""):
async def send_tool_message(
self, message: str, title: str = "", image: Optional[str] = None
):
"""
发送工具消息
"""
@@ -261,5 +263,6 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta):
username=self._username,
title=title,
text=message,
image=image,
)
)

View File

@@ -2,7 +2,7 @@
from typing import Optional, Type
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool
from app.log import logger
@@ -15,42 +15,64 @@ class SendMessageInput(BaseModel):
...,
description="Clear explanation of why this tool is being used in the current context",
)
message: str = Field(
...,
message: Optional[str] = Field(
None,
description="The message content to send to the user (should be clear and informative)",
)
message_type: Optional[str] = Field(
None,
description="Title of the message, a short summary of the message content",
)
image_url: Optional[str] = Field(
None,
description="Optional image URL to send together with the message on channels that support images (such as Telegram and Slack)",
)
@model_validator(mode="after")
def validate_payload(self):
if not self.message and not self.message_type and not self.image_url:
raise ValueError("message、message_type、image_url 至少需要提供一个")
return self
class SendMessageTool(MoviePilotTool):
name: str = "send_message"
description: str = "Send notification message to the user through configured notification channels (Telegram, Slack, WeChat, etc.). Used to inform users about operation results, errors, or important updates."
description: str = "Send notification message to the user through configured notification channels (Telegram, Slack, WeChat, etc.). Supports optional image_url on channels that can send images. Used to inform users about operation results, errors, important updates, or proactively send a relevant image."
args_schema: Type[BaseModel] = SendMessageInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据消息参数生成友好的提示消息"""
message = kwargs.get("message", "")
message = kwargs.get("message", "") or ""
title = kwargs.get("message_type") or ""
image_url = kwargs.get("image_url")
# 截断过长的消息
if len(message) > 50:
message = message[:50] + "..."
if title and image_url:
return f"正在发送图文消息: [{title}] {message}"
if title:
return f"正在发送消息: [{title}] {message}"
if image_url:
return f"正在发送图片消息: {message}"
return f"正在发送消息: {message}"
async def run(
self, message: str, message_type: Optional[str] = None, **kwargs
self,
message: Optional[str] = None,
message_type: Optional[str] = None,
image_url: Optional[str] = None,
**kwargs,
) -> str:
title = message_type or ""
logger.info(f"执行工具: {self.name}, 参数: title={title}, message={message}")
title = message_type or ("图片" if image_url and not message else "")
text = message or ""
logger.info(
f"执行工具: {self.name}, 参数: title={title}, message={text}, image_url={image_url}"
)
try:
await self.send_tool_message(message, title=title)
await self.send_tool_message(text, title=title, image=image_url)
return "消息已发送"
except Exception as e:
logger.error(f"发送消息失败: {e}")