refine agent subscription defaults and silent tool prompts

This commit is contained in:
jxxghp
2026-04-26 08:51:56 +08:00
parent 0277288a41
commit b5979b9b09
5 changed files with 193 additions and 55 deletions
+1
View File
@@ -60,6 +60,7 @@ Core Capabilities:
2. Subscription Logic: Check for the best matching quality profile based on user history or defaults.
3. Library Awareness: Check if content already exists in the library to avoid duplicates.
4. Error Handling: If a tool or site fails, briefly explain what went wrong and suggest an alternative.
5. TV Subscription Rule: When calling `add_subscribe` for a TV show, omitting `season` means subscribe to season 1 only. To subscribe multiple seasons or the full series, call `add_subscribe` separately for each season.
</media_management_rules>
<markdown_spec>
+12 -10
View File
@@ -82,11 +82,13 @@ class PromptManager:
verbose_spec = ""
if not settings.AI_AGENT_VERBOSE:
verbose_spec = (
"\n\n[Important Instruction] STRICTLY ENFORCED: DO NOT output any conversational "
"text, thinking processes, or explanations before or during tool calls. Call tools "
"directly without any transitional phrases. "
"You MUST remain completely silent until the task is completely finished. "
"DO NOT output any content whatsoever until your final summary reply."
"\n\n[Important Instruction] STRICTLY ENFORCED WHEN VERBOSE MODE IS OFF: "
"If tools are needed, DO NOT output any conversational text, explanations, progress updates, "
"or acknowledgements before the first tool call or between tool calls. "
"Call tools directly without any transitional phrases. "
"You MUST remain completely silent until all required tools have finished and you have the final result. "
"Only then may you send one final user-facing reply. "
"DO NOT output any intermediate content whatsoever."
)
# MoviePilot系统信息
@@ -193,18 +195,18 @@ class PromptManager:
def _generate_button_choice_instructions(
channel: MessageChannel = None,
) -> str:
if channel and ChannelCapabilityManager.supports_buttons(
if (
channel
) and ChannelCapabilityManager.supports_callbacks(channel):
and ChannelCapabilityManager.supports_buttons(channel)
and ChannelCapabilityManager.supports_callbacks(channel)
):
return (
"- User questions: If you need the user to choose from a few clear options, "
"call `ask_user_choice` to send button options. After the user clicks a button, "
"the selected value will come back as the user's next message. After calling this tool, "
"wait for the user's selection instead of repeating the question in plain text."
)
return (
"- User questions: When you truly need user input, ask briefly in plain text."
)
return "- User questions: When you truly need user input, ask briefly in plain text."
def clear_cache(self):
"""
+111 -45
View File
@@ -12,36 +12,74 @@ from app.schemas.types import MediaType
class AddSubscribeInput(BaseModel):
"""添加订阅工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
title: str = Field(..., description="The title of the media to subscribe to (e.g., 'The Matrix', 'Breaking Bad')")
year: str = Field(..., description="Release year of the media (required for accurate identification)")
media_type: str = Field(...,
description="Allowed values: movie, tv")
season: Optional[int] = Field(None,
description="Season number for TV shows (optional, if not specified will subscribe to all seasons)")
tmdb_id: Optional[int] = Field(None,
description="TMDB database ID for precise media identification (optional, can be obtained from search_media tool)")
douban_id: Optional[str] = Field(None,
description="Douban ID for precise media identification (optional, alternative to tmdb_id)")
start_episode: Optional[int] = Field(None,
description="Starting episode number for TV shows (optional, defaults to 1 if not specified)")
total_episode: Optional[int] = Field(None,
description="Total number of episodes for TV shows (optional, will be auto-detected from TMDB if not specified)")
quality: Optional[str] = Field(None,
description="Quality filter as regular expression (optional, e.g., 'BluRay|WEB-DL|HDTV')")
resolution: Optional[str] = Field(None,
description="Resolution filter as regular expression (optional, e.g., '1080p|720p|2160p')")
effect: Optional[str] = Field(None,
description="Effect filter as regular expression (optional, e.g., 'HDR|DV|SDR')")
filter_groups: Optional[List[str]] = Field(None,
description="List of filter rule group names to apply (optional, can be obtained from query_rule_groups tool)")
sites: Optional[List[int]] = Field(None,
description="List of site IDs to search from (optional, can be obtained from query_sites tool)")
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
title: str = Field(
...,
description="The title of the media to subscribe to (e.g., 'The Matrix', 'Breaking Bad')",
)
year: str = Field(
...,
description="Release year of the media (required for accurate identification)",
)
media_type: str = Field(..., description="Allowed values: movie, tv")
season: Optional[int] = Field(
None,
description=(
"Season number for TV shows (optional). If omitted, the subscription defaults to season 1 only. "
"To subscribe multiple seasons or the full series, call this tool separately for each season."
),
)
tmdb_id: Optional[int] = Field(
None,
description="TMDB database ID for precise media identification (optional, can be obtained from search_media tool)",
)
douban_id: Optional[str] = Field(
None,
description="Douban ID for precise media identification (optional, alternative to tmdb_id)",
)
start_episode: Optional[int] = Field(
None,
description="Starting episode number for TV shows (optional, defaults to 1 if not specified)",
)
total_episode: Optional[int] = Field(
None,
description="Total number of episodes for TV shows (optional, will be auto-detected from TMDB if not specified)",
)
quality: Optional[str] = Field(
None,
description="Quality filter as regular expression (optional, e.g., 'BluRay|WEB-DL|HDTV')",
)
resolution: Optional[str] = Field(
None,
description="Resolution filter as regular expression (optional, e.g., '1080p|720p|2160p')",
)
effect: Optional[str] = Field(
None,
description="Effect filter as regular expression (optional, e.g., 'HDR|DV|SDR')",
)
filter_groups: Optional[List[str]] = Field(
None,
description="List of filter rule group names to apply (optional, can be obtained from query_rule_groups tool)",
)
sites: Optional[List[int]] = Field(
None,
description="List of site IDs to search from (optional, can be obtained from query_sites tool)",
)
class AddSubscribeTool(MoviePilotTool):
name: str = "add_subscribe"
description: str = "Add media subscription to create automated download rules for movies and TV shows. The system will automatically search and download new episodes or releases based on the subscription criteria. Supports advanced filtering options like quality, resolution, and effect filters using regular expressions."
description: str = (
"Add media subscription to create automated download rules for movies and TV shows. "
"The system will automatically search and download new episodes or releases based on the subscription criteria. "
"For TV shows, omitting `season` subscribes season 1 only by default; to subscribe multiple seasons or "
"the full series, call this tool once per season. Supports advanced filtering options like quality, "
"resolution, and effect filters using regular expressions."
)
args_schema: Type[BaseModel] = AddSubscribeInput
def get_tool_message(self, **kwargs) -> Optional[str]:
@@ -50,7 +88,7 @@ class AddSubscribeTool(MoviePilotTool):
year = kwargs.get("year", "")
media_type = kwargs.get("media_type", "")
season = kwargs.get("season")
message = f"正在添加订阅: {title}"
if year:
message += f" ({year})"
@@ -58,44 +96,64 @@ class AddSubscribeTool(MoviePilotTool):
message += f" [{media_type}]"
if season:
message += f"{season}"
elif media_type == "tv":
message += " 第1季(默认)"
return message
async def run(self, title: str, year: str, media_type: str,
season: Optional[int] = None, tmdb_id: Optional[int] = None,
douban_id: Optional[str] = None,
start_episode: Optional[int] = None, total_episode: Optional[int] = None,
quality: Optional[str] = None, resolution: Optional[str] = None,
effect: Optional[str] = None, filter_groups: Optional[List[str]] = None,
sites: Optional[List[int]] = None, **kwargs) -> str:
async def run(
self,
title: str,
year: str,
media_type: str,
season: Optional[int] = None,
tmdb_id: Optional[int] = None,
douban_id: Optional[str] = None,
start_episode: Optional[int] = None,
total_episode: Optional[int] = None,
quality: Optional[str] = None,
resolution: Optional[str] = None,
effect: Optional[str] = None,
filter_groups: Optional[List[str]] = None,
sites: Optional[List[int]] = None,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: title={title}, year={year}, media_type={media_type}, "
f"season={season}, tmdb_id={tmdb_id}, douban_id={douban_id}, start_episode={start_episode}, "
f"total_episode={total_episode}, quality={quality}, resolution={resolution}, "
f"effect={effect}, filter_groups={filter_groups}, sites={sites}")
f"effect={effect}, filter_groups={filter_groups}, sites={sites}"
)
try:
subscribe_chain = SubscribeChain()
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
effective_season = (
season
if season is not None
else 1
if media_type_enum == MediaType.TV
else None
)
# 构建额外的订阅参数
subscribe_kwargs = {}
if start_episode is not None:
subscribe_kwargs['start_episode'] = start_episode
subscribe_kwargs["start_episode"] = start_episode
if total_episode is not None:
subscribe_kwargs['total_episode'] = total_episode
subscribe_kwargs["total_episode"] = total_episode
if quality:
subscribe_kwargs['quality'] = quality
subscribe_kwargs["quality"] = quality
if resolution:
subscribe_kwargs['resolution'] = resolution
subscribe_kwargs["resolution"] = resolution
if effect:
subscribe_kwargs['effect'] = effect
subscribe_kwargs["effect"] = effect
if filter_groups:
subscribe_kwargs['filter_groups'] = filter_groups
subscribe_kwargs["filter_groups"] = filter_groups
if sites:
subscribe_kwargs['sites'] = sites
subscribe_kwargs["sites"] = sites
sid, message = await subscribe_chain.async_add(
mtype=media_type_enum,
@@ -105,13 +163,21 @@ class AddSubscribeTool(MoviePilotTool):
doubanid=douban_id,
season=season,
username=self._user_id,
**subscribe_kwargs
**subscribe_kwargs,
)
if sid:
if message and "已存在" in message:
return f"订阅已存在:{title} ({year})。如需修改参数请先删除旧订阅。"
result_msg = f"订阅已存在:{title} ({year})"
if effective_season is not None:
result_msg += f"{effective_season}"
result_msg += "。如需修改参数请先删除旧订阅。"
return result_msg
result_msg = f"成功添加订阅:{title} ({year})"
if effective_season is not None:
result_msg += f"{effective_season}"
if season is None:
result_msg += "(未指定季号,默认按第一季订阅)"
if subscribe_kwargs:
params = []
if start_episode is not None: