mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-10 07:54:14 +08:00
Fix Agent task relative-time validation (#6146)
This commit is contained in:
@@ -60,13 +60,12 @@ class CreateAgentTaskInput(BaseModel):
|
||||
if not self.name or not self.content:
|
||||
raise ValueError("name 和 content 不能只包含空白字符")
|
||||
if self.trigger_type == "date":
|
||||
if (self.trigger is None) == (self.delay_minutes is None):
|
||||
raise ValueError("date 任务必须且只能提供 trigger 或 delay_minutes 之一")
|
||||
if self.delay_minutes is not None:
|
||||
timezone = pytz.timezone(settings.TZ)
|
||||
self.trigger = (
|
||||
datetime.now(timezone) + timedelta(minutes=self.delay_minutes)
|
||||
).isoformat(timespec="seconds")
|
||||
# LangChain 会在 run() 前后各校验一次,延迟时间在持久化前统一计算。
|
||||
self.trigger = None
|
||||
return self
|
||||
if self.trigger is None:
|
||||
raise ValueError("date 任务必须提供 trigger 或 delay_minutes")
|
||||
elif self.trigger is None or self.delay_minutes is not None:
|
||||
raise ValueError("cron 任务必须提供 trigger,且不能提供 delay_minutes")
|
||||
self.trigger_type, self.trigger = TimerUtils.normalize_schedule_trigger(
|
||||
@@ -102,6 +101,18 @@ class CreateAgentTaskTool(MoviePilotTool):
|
||||
"""持久化任务并立即注册到运行时调度器。"""
|
||||
from app.scheduler import Scheduler
|
||||
|
||||
trigger_value = payload.trigger
|
||||
if payload.trigger_type == "date" and payload.delay_minutes is not None:
|
||||
timezone = pytz.timezone(settings.TZ)
|
||||
trigger_value = (
|
||||
datetime.now(timezone) + timedelta(minutes=payload.delay_minutes)
|
||||
).isoformat(timespec="seconds")
|
||||
_, trigger_value = TimerUtils.normalize_schedule_trigger(
|
||||
trigger_type=payload.trigger_type,
|
||||
trigger_value=trigger_value,
|
||||
timezone_name=settings.TZ,
|
||||
require_future=True,
|
||||
)
|
||||
chat = AgentChatOper().get(
|
||||
session_id=self._session_id,
|
||||
user_id=self._user_id,
|
||||
@@ -110,8 +121,8 @@ class CreateAgentTaskTool(MoviePilotTool):
|
||||
name=payload.name.strip(),
|
||||
content=payload.content.strip(),
|
||||
trigger_type=payload.trigger_type,
|
||||
cron_expression=payload.trigger if payload.trigger_type == "cron" else None,
|
||||
run_at=payload.trigger if payload.trigger_type == "date" else None,
|
||||
cron_expression=trigger_value if payload.trigger_type == "cron" else None,
|
||||
run_at=trigger_value if payload.trigger_type == "date" else None,
|
||||
user_id=str(self._user_id),
|
||||
username=self._username or (chat.username if chat else None),
|
||||
session_id=str(self._session_id),
|
||||
|
||||
@@ -61,13 +61,11 @@ class UpdateAgentTaskInput(BaseModel):
|
||||
if self.trigger_type is None:
|
||||
raise ValueError("修改触发配置时必须提供 trigger_type")
|
||||
if self.trigger_type == "date":
|
||||
if (self.trigger is None) == (self.delay_minutes is None):
|
||||
raise ValueError("date 任务必须且只能提供 trigger 或 delay_minutes 之一")
|
||||
if self.delay_minutes is not None:
|
||||
timezone = pytz.timezone(settings.TZ)
|
||||
self.trigger = (
|
||||
datetime.now(timezone) + timedelta(minutes=self.delay_minutes)
|
||||
).isoformat(timespec="seconds")
|
||||
# 保持校验幂等,具体绝对时间在更新调度前只计算一次。
|
||||
self.trigger = None
|
||||
elif self.trigger is None:
|
||||
raise ValueError("date 任务必须提供 trigger 或 delay_minutes")
|
||||
elif self.trigger is None or self.delay_minutes is not None:
|
||||
raise ValueError("cron 任务必须提供 trigger,且不能提供 delay_minutes")
|
||||
if all(
|
||||
@@ -112,9 +110,16 @@ class UpdateAgentTaskTool(MoviePilotTool):
|
||||
return {"error": f"Agent 定时任务 {payload.task_id} 正在执行,请稍后再修改"}
|
||||
|
||||
trigger_type = payload.trigger_type or task.trigger_type
|
||||
trigger_value = payload.trigger or (
|
||||
task.cron_expression if trigger_type == "cron" else task.run_at
|
||||
)
|
||||
trigger_value = payload.trigger
|
||||
if trigger_type == "date" and payload.delay_minutes is not None:
|
||||
timezone = pytz.timezone(settings.TZ)
|
||||
trigger_value = (
|
||||
datetime.now(timezone) + timedelta(minutes=payload.delay_minutes)
|
||||
).isoformat(timespec="seconds")
|
||||
if trigger_value is None:
|
||||
trigger_value = (
|
||||
task.cron_expression if trigger_type == "cron" else task.run_at
|
||||
)
|
||||
enabled = task.enabled if payload.enabled is None else payload.enabled
|
||||
normalized_type, normalized_trigger = TimerUtils.normalize_schedule_trigger(
|
||||
trigger_type=trigger_type,
|
||||
@@ -128,7 +133,7 @@ class UpdateAgentTaskTool(MoviePilotTool):
|
||||
update_payload["name"] = payload.name.strip()
|
||||
if payload.content is not None:
|
||||
update_payload["content"] = payload.content.strip()
|
||||
if payload.trigger is not None:
|
||||
if payload.trigger_type is not None:
|
||||
update_payload.update(
|
||||
{
|
||||
"trigger_type": normalized_type,
|
||||
|
||||
@@ -195,14 +195,12 @@ async def test_agent_task_tools_manage_persistent_schedule(monkeypatch) -> None:
|
||||
monkeypatch.setattr("app.scheduler.Scheduler", lambda: fake_scheduler)
|
||||
|
||||
create_tool = _build_tool(CreateAgentTaskTool, user_id)
|
||||
created = json.loads(
|
||||
await create_tool.run(
|
||||
name="十分钟后检查",
|
||||
content="检查示例电影是否有资源,不要自动下载",
|
||||
trigger_type="date",
|
||||
delay_minutes=10,
|
||||
)
|
||||
)
|
||||
created = json.loads(await create_tool.ainvoke({
|
||||
"name": "十分钟后检查",
|
||||
"content": "检查示例电影是否有资源,不要自动下载",
|
||||
"trigger_type": "date",
|
||||
"delay_minutes": 10,
|
||||
}))
|
||||
task_id = created["id"]
|
||||
assert created["enabled"] is True
|
||||
assert datetime.fromisoformat(created["run_at"]) > datetime.now(
|
||||
@@ -217,6 +215,16 @@ async def test_agent_task_tools_manage_persistent_schedule(monkeypatch) -> None:
|
||||
assert queried["tasks"][0]["content"].startswith("检查示例电影")
|
||||
|
||||
update_tool = _build_tool(UpdateAgentTaskTool, user_id)
|
||||
delayed_update = json.loads(await update_tool.ainvoke({
|
||||
"task_id": task_id,
|
||||
"trigger_type": "date",
|
||||
"delay_minutes": 20,
|
||||
}))
|
||||
assert delayed_update["trigger_type"] == "date"
|
||||
assert datetime.fromisoformat(delayed_update["run_at"]) > datetime.now(
|
||||
pytz.timezone(settings.TZ)
|
||||
)
|
||||
|
||||
updated = json.loads(
|
||||
await update_tool.run(
|
||||
task_id=task_id,
|
||||
|
||||
Reference in New Issue
Block a user