Files
MoviePilot/app/db/models/agenttask.py
2026-07-19 20:19:06 +08:00

171 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import datetime
from typing import Optional
from sqlalchemy import Boolean, Column, Index, Integer, String, Text
from sqlalchemy.orm import Session
from app.db import Base, db_query, db_update, get_id_column
class AgentTask(Base):
"""
Agent 自主定时任务表。
"""
id = get_id_column()
# 任务名称
name = Column(String, nullable=False)
# 交给 Agent 执行的完整任务内容
content = Column(Text, nullable=False)
# 触发类型date-单次触发cron-周期触发
trigger_type = Column(String, nullable=False)
# 标准五段 cron 表达式
cron_expression = Column(String)
# 单次触发时间,使用带时区的 ISO 8601 格式
run_at = Column(String)
# 是否继续接受调度
enabled = Column(Boolean, nullable=False, default=True)
# 创建任务的用户与会话上下文
user_id = Column(String, nullable=False)
username = Column(String)
session_id = Column(String, nullable=False)
channel = Column(String)
source = Column(String)
original_chat_id = Column(String)
# 最近一次执行状态与结果
last_status = Column(String, nullable=False, default="waiting")
last_run_at = Column(String)
last_result = Column(Text)
run_count = Column(Integer, nullable=False, default=0)
created_at = Column(String, nullable=False)
updated_at = Column(String, nullable=False)
__table_args__ = (
Index("ix_agenttask_enabled", "enabled"),
Index("ix_agenttask_user_created", "user_id", "created_at", "id"),
)
@classmethod
@db_update
def add_task(cls, db: Session, **kwargs: object) -> int:
"""
新增 Agent 定时任务并返回任务 ID。
"""
task = cls(**kwargs)
db.add(task)
db.flush()
return task.id
@classmethod
@db_query
def get_for_user(
cls,
db: Session,
task_id: int,
user_id: Optional[str] = None,
) -> Optional["AgentTask"]:
"""
按任务 ID 和可选用户 ID 查询 Agent 定时任务。
"""
query = db.query(cls).filter(cls.id == task_id)
if user_id is not None:
query = query.filter(cls.user_id == user_id)
return query.first()
@classmethod
@db_query
def list_for_user(
cls,
db: Session,
user_id: Optional[str] = None,
enabled: Optional[bool] = None,
) -> list["AgentTask"]:
"""
按用户和启用状态查询 Agent 定时任务。
"""
query = db.query(cls)
if user_id is not None:
query = query.filter(cls.user_id == user_id)
if enabled is not None:
query = query.filter(cls.enabled.is_(enabled))
return query.order_by(cls.created_at.desc(), cls.id.desc()).all()
@classmethod
@db_update
def update_task(
cls,
db: Session,
task_id: int,
payload: dict,
user_id: Optional[str] = None,
) -> bool:
"""
按任务 ID 和可选用户 ID 更新 Agent 定时任务。
"""
query = db.query(cls).filter(cls.id == task_id)
if user_id is not None:
query = query.filter(cls.user_id == user_id)
return bool(query.update(payload))
@classmethod
@db_update
def delete_task(
cls,
db: Session,
task_id: int,
user_id: Optional[str] = None,
) -> bool:
"""
按任务 ID 和可选用户 ID 删除 Agent 定时任务。
"""
query = db.query(cls).filter(cls.id == task_id)
if user_id is not None:
query = query.filter(cls.user_id == user_id)
return bool(query.delete())
@classmethod
@db_update
def mark_running(cls, db: Session, task_id: int, run_at: str) -> bool:
"""
将可执行任务标记为运行中。
"""
updated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return bool(
db.query(cls)
.filter(
cls.id == task_id,
cls.enabled.is_(True),
cls.last_status != "running",
)
.update(
{
"last_status": "running",
"last_run_at": run_at,
"updated_at": updated_at,
}
)
)
@classmethod
@db_update
def finish_task(
cls,
db: Session,
task_id: int,
success: bool,
result: str,
disable: bool = False,
) -> bool:
"""
记录 Agent 定时任务执行结果,并按需关闭单次任务。
"""
payload = {
"last_status": "success" if success else "failed",
"last_result": result,
"run_count": cls.run_count + 1,
"updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
if disable:
payload["enabled"] = False
return bool(db.query(cls).filter(cls.id == task_id).update(payload))