mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 07:56:52 +08:00
refactor: complete durable transfer execution settlement
This commit is contained in:
@@ -39,10 +39,11 @@ task_types:
|
||||
- "Use `query_transfer_history` with status='failed' to find the record with id={history_id} and understand the failure details such as source path, error message, and media info."
|
||||
- "Analyze the error message to determine the best retry strategy."
|
||||
- "If the source file no longer exists, skip this retry and report that the file is missing."
|
||||
- "Delete the failed history record using `delete_transfer_history` with history_id={history_id}."
|
||||
- "Re-identify the media using `recognize_media` with the source file path. For audio files, set media_type='music' and preserve artist/title/album context."
|
||||
- "If recognition fails, try `search_media` with keywords from the filename. For music, distinguish recording, album, and browse-only artist results."
|
||||
- "Re-transfer using `transfer_file` with the source path and exact identity fields. Reuse media_source + media_id for every media type, plus media_type + music_type for music."
|
||||
- "Call `delete_transfer_history` with history_id={history_id}. Durable records are not deleted: the tool submits them to the persistent retry scheduler."
|
||||
- "If `delete_transfer_history` reports that a durable retry was accepted or rejected, stop and report the exact scheduler result. Do not call `transfer_file`; do not delete the target, history, or retry evidence."
|
||||
- "Only for a legacy history that was actually deleted, re-identify the media using `recognize_media` with the source file path. For audio files, set media_type='music' and preserve artist/title/album context."
|
||||
- "If legacy recognition fails, try `search_media` with keywords from the filename. For music, distinguish recording, album, and browse-only artist results."
|
||||
- "Re-transfer only the deleted legacy history using `transfer_file` with the source path and exact identity fields. Reuse media_source + media_id for every media type, plus media_type + music_type for music."
|
||||
- "Report the final result."
|
||||
batch_transfer_failed_retry:
|
||||
header: "[System Task - Batch Transfer Failed Retry]"
|
||||
@@ -56,7 +57,7 @@ task_types:
|
||||
- "Use `query_transfer_history` with status='failed' to find all records with these IDs and understand the failure details."
|
||||
- "Group records by exact media identity and source directory before retrying. Do not assume all selected files belong to one media."
|
||||
- "If the error is about media recognition, identify each group once using `recognize_media` or `search_media`, then reuse that result inside the group. Album tracks should normally be retried from the shared album directory with the album identity."
|
||||
- "For each failed record, delete the old history entry with `delete_transfer_history` and re-transfer using `transfer_file`."
|
||||
- "For each failed record, call `delete_transfer_history`. Durable records are submitted to the persistent retry scheduler, and that result is final for this task: report its exact accepted or rejected state and do not call `transfer_file` or delete its evidence. Only an actually deleted legacy history may be re-transferred with `transfer_file`."
|
||||
- "Report how many retries succeeded and how many still failed."
|
||||
task_rules:
|
||||
- "Within one verified group, do NOT call `recognize_media` or `search_media` repeatedly for each file. A music recording is one track; a music album is one multi-track directory; an artist is never a transfer target."
|
||||
@@ -90,8 +91,9 @@ task_types:
|
||||
- "If the current recognition is wrong or the record should be reorganized, determine the correct media identity first."
|
||||
- "Prefer `recognize_media` with the source path. If recognition is not reliable, use `search_media` with keywords from filename, title, or year."
|
||||
- "Only continue when you have high confidence in the target media."
|
||||
- "Before re-organizing, delete the old transfer history record with `delete_transfer_history` so the system will not skip the source file."
|
||||
- "Then use `transfer_file` to organize the source path directly."
|
||||
- "Before re-organizing, call `delete_transfer_history`. Durable records are not deleted: the tool submits them to the persistent retry scheduler."
|
||||
- "If `delete_transfer_history` reports that a durable retry was accepted or rejected, stop for that record and report the exact scheduler result. Do not call `transfer_file`; do not delete the target, history, or retry evidence. Only a legacy history deletion may be followed by `transfer_file`."
|
||||
- "For a legacy history that was actually deleted, use `transfer_file` to organize the source path directly."
|
||||
- "When calling `transfer_file`, reuse known context when appropriate: source storage, target path, target storage, transfer mode, season, media_source, media_id, media_type, and music_type. For an album, retry the album directory once with the album identity when the records share that directory."
|
||||
- "If this record is already correct and no re-organize is needed, do not perform destructive actions; simply report that no change is necessary."
|
||||
task_rules:
|
||||
@@ -116,8 +118,9 @@ task_types:
|
||||
- "For each group, decide whether the current recognition is trustworthy."
|
||||
- "If multiple records clearly belong to the same movie, series, or music album, identify the media once with `recognize_media` or `search_media`, then reuse that result for the related records. A recording remains a single-track target, and an artist is browse-only."
|
||||
- "If a source file no longer exists or cannot be safely processed, skip that record and note the reason."
|
||||
- "Before re-organizing a record, delete the old transfer history record with `delete_transfer_history` so the system will not skip the source file."
|
||||
- "Then use `transfer_file` to organize the source path directly."
|
||||
- "Before re-organizing each record, call `delete_transfer_history`. Durable records are not deleted: the tool submits each task to the persistent retry scheduler."
|
||||
- "For each durable result, report the exact accepted or rejected scheduler state and stop processing that record. Do not call `transfer_file`; do not delete its target, history, or retry evidence."
|
||||
- "Only after a legacy history was actually deleted, use `transfer_file` to organize that source path directly."
|
||||
- "When calling `transfer_file`, reuse known context when appropriate: source storage, target path, target storage, transfer mode, season, media_source, media_id, media_type, and music_type. Prefer one directory transfer for a verified complete album instead of treating each track as an unrelated media item."
|
||||
- "If a record is already correct and no re-organize is needed, do not perform destructive actions; simply mark it as skipped."
|
||||
- "Report only the aggregate outcome, including how many records succeeded, skipped, and failed."
|
||||
|
||||
@@ -7,8 +7,13 @@ from pydantic import BaseModel, Field
|
||||
|
||||
from app.agent.tools.base import MoviePilotTool
|
||||
from app.agent.tools.tags import ToolTag
|
||||
from app.chain.storage import StorageChain
|
||||
from app.application.agentdata import get_agent_transfer_history_port
|
||||
from app.application.chain.data import get_chain_transfer_execution_port
|
||||
from app.application.transfer_execution import (
|
||||
TransferExecutionCommand,
|
||||
TransferRetryRequestResult,
|
||||
)
|
||||
from app.chain.storage import StorageChain
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.workflow import FileItem
|
||||
|
||||
@@ -29,6 +34,22 @@ def _delete_history_destination_file(fileitem: FileItem) -> tuple[bool, bool]:
|
||||
return True, bool(storage_chain.delete_media_file(fileitem))
|
||||
|
||||
|
||||
def _request_transfer_retry(
|
||||
*,
|
||||
history_id: int,
|
||||
task_id: str,
|
||||
user_id: str,
|
||||
) -> TransferRetryRequestResult:
|
||||
"""在线程池中登记 durable 重试,避免 Agent 事件循环执行同步数据库 I/O。"""
|
||||
return TransferExecutionCommand(
|
||||
get_chain_transfer_execution_port()
|
||||
).request_retry(
|
||||
task_id=task_id,
|
||||
reason=f"Agent 请求重试整理历史 #{history_id}",
|
||||
requested_by=f"agent:{user_id or 'unknown'}",
|
||||
)
|
||||
|
||||
|
||||
class DeleteTransferHistoryTool(MoviePilotTool):
|
||||
name: str = "delete_transfer_history"
|
||||
tags: list[str] = [
|
||||
@@ -37,9 +58,10 @@ class DeleteTransferHistoryTool(MoviePilotTool):
|
||||
ToolTag.Admin,
|
||||
]
|
||||
description: str = (
|
||||
"Delete a specific transfer history record by its ID. For non-successful-move records with an old "
|
||||
"destination file, the tool removes that media-library file before deleting the history record. This is "
|
||||
"useful before retrying or re-organizing because the system skips files that already have transfer history."
|
||||
"Request a safe retry for durable transfer history, or delete a legacy transfer history record by its ID. "
|
||||
"Durable records keep their files and history and are retried only by the persistent scheduler. For legacy "
|
||||
"non-successful-move records, the tool removes the old destination before deleting the history. If a durable "
|
||||
"retry is accepted or rejected, stop and report that result; do not call transfer_file for the same record."
|
||||
)
|
||||
args_schema: Type[BaseModel] = DeleteTransferHistoryInput
|
||||
require_admin: bool = True
|
||||
@@ -58,6 +80,22 @@ class DeleteTransferHistoryTool(MoviePilotTool):
|
||||
if not history:
|
||||
return f"错误:整理历史记录不存在,ID={history_id}"
|
||||
|
||||
task_id = getattr(history, "transfer_task_id", None)
|
||||
if task_id:
|
||||
retry = await self.run_blocking(
|
||||
"db",
|
||||
_request_transfer_retry,
|
||||
history_id=history_id,
|
||||
task_id=task_id,
|
||||
user_id=self._user_id,
|
||||
)
|
||||
outcome = "已登记" if retry.accepted else "未登记"
|
||||
return (
|
||||
f"durable 整理任务{outcome}重试:ID={history_id},"
|
||||
f"task_id={task_id},state={retry.state.value},{retry.message}。"
|
||||
"已保留目标文件、历史记录和失败计数;不要调用 transfer_file。"
|
||||
)
|
||||
|
||||
title = history.title or "未知"
|
||||
src = history.src or "未知"
|
||||
status = "成功" if history.status else "失败"
|
||||
|
||||
Reference in New Issue
Block a user