fix(agent): isolate web and storage blocking I/O

This commit is contained in:
InfinityPacer
2026-08-23 13:06:30 +08:00
parent 43c173a0e7
commit d11c2fb301
7 changed files with 558 additions and 56 deletions
+3 -3
View File
@@ -9,7 +9,7 @@ import uuid
import warnings
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Any, Callable, Dict, List, Optional
from typing import Any, Awaitable, Callable, Dict, List, Optional
from fastapi.concurrency import run_in_threadpool
from langchain.agents import create_agent
@@ -2572,7 +2572,7 @@ class _MessageTask:
allow_message_tools: bool = True
output_callback: Optional[Callable[[str], None]] = None
protected_output_callback: Optional[Callable[[str], Optional[bool]]] = None
message_callback: Optional[Callable[[Any], None]] = None
message_callback: Optional[Callable[[Any], Awaitable[None] | None]] = None
agent_factory: Optional[Callable[..., MoviePilotAgent]] = None
agent_setup: Optional[Callable[[MoviePilotAgent], None]] = None
completion_future: Optional[asyncio.Future] = None
@@ -2834,7 +2834,7 @@ class AgentManager:
allow_message_tools: bool = True,
output_callback: Optional[Callable[[str], None]] = None,
protected_output_callback: Optional[Callable[[str], Optional[bool]]] = None,
message_callback: Optional[Callable[[Any], None]] = None,
message_callback: Optional[Callable[[Any], Awaitable[None] | None]] = None,
agent_factory: Optional[Callable[..., MoviePilotAgent]] = None,
agent_setup: Optional[Callable[[MoviePilotAgent], None]] = None,
wait_for_completion: bool = False,
+4 -1
View File
@@ -1,4 +1,5 @@
import asyncio
import inspect
import json
import threading
from abc import ABCMeta, abstractmethod
@@ -646,7 +647,9 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta):
self._channel == NotificationChannel.WebAgent.value
and callable(callback)
):
callback(message)
callback_result = callback(message)
if inspect.isawaitable(callback_result):
await callback_result
return
if not self._channel or not self._source:
@@ -1,5 +1,6 @@
"""删除整理历史记录工具"""
import asyncio
from typing import Optional, Type
from pydantic import BaseModel, Field
@@ -20,6 +21,14 @@ class DeleteTransferHistoryInput(BaseModel):
)
def _delete_history_destination_file(fileitem: FileItem) -> tuple[bool, bool]:
"""在存储 worker 内完成旧目标检查和删除,保持历史删除前的顺序。"""
storage_chain = StorageChain()
if not storage_chain.exists(fileitem):
return False, False
return True, bool(storage_chain.delete_media_file(fileitem))
class DeleteTransferHistoryTool(MoviePilotTool):
name: str = "delete_transfer_history"
tags: list[str] = [
@@ -55,9 +64,21 @@ class DeleteTransferHistoryTool(MoviePilotTool):
deleted_dest = False
if history.dest_fileitem and not (history.status and history.mode == "move"):
dest_fileitem = FileItem(**history.dest_fileitem)
storage_chain = StorageChain()
if storage_chain.exists(dest_fileitem):
if not storage_chain.delete_media_file(dest_fileitem):
try:
destination_exists, destination_deleted = await self.run_blocking(
"storage",
_delete_history_destination_file,
dest_fileitem,
)
except asyncio.CancelledError:
logger.warning(
"删除整理历史的旧媒体文件等待已取消,底层文件操作可能仍在继续,"
"请确认实际状态后再重试,历史记录尚未删除,path=%s",
dest_fileitem.path,
)
raise
if destination_exists:
if not destination_deleted:
return f"错误:旧媒体库文件删除失败,路径={dest_fileitem.path}"
deleted_dest = True
await transferhis.async_delete(history_id)