Files
moss-ai/mcp/didatodolist-mcp/tools/task_tools.py

941 lines
35 KiB
Python
Raw Normal View History

2025-12-15 22:05:56 +08:00
"""
任务相关MCP工具
"""
from typing import Dict, List, Optional, Any, Union
from datetime import datetime, timedelta
import pytz
from fastmcp import FastMCP
from .adapter import adapter, APIError
# --- 模块级辅助函数 ---
_completed_columns = set()
def _parse_date(date_str: Optional[str]) -> Optional[datetime]:
"""解析日期字符串为datetime对象将UTC时间转换为北京时间"""
if not date_str:
return None
local_tz = pytz.timezone('Asia/Shanghai')
try:
# 处理ISO格式
if 'T' in date_str:
base_time = date_str.split('.')[0]
if date_str.endswith('Z') or '+0000' in date_str:
# UTC时间需要转换
dt = datetime.strptime(base_time.replace('T', ' '), "%Y-%m-%d %H:%M:%S")
dt = pytz.UTC.localize(dt)
return dt.astimezone(local_tz)
else:
# 尝试使用fromisoformat
try:
dt = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
return dt.astimezone(local_tz)
except ValueError:
# 假定为本地时间
dt = datetime.strptime(base_time.replace('T', ' '), "%Y-%m-%d %H:%M:%S")
return local_tz.localize(dt)
except ValueError:
pass
try:
# 标准格式 (假定为本地时间)
dt = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
return local_tz.localize(dt)
except ValueError:
# 尝试其他可能的格式
try:
dt = datetime.strptime(date_str, "%Y-%m-%d")
return local_tz.localize(dt)
except ValueError:
return None
def _format_date_for_api(date_str: Optional[str]) -> Optional[str]:
"""
'YYYY-MM-DD HH:MM:SS'格式的日期转换为API所需的'YYYY-MM-DDThh:mm:ss.000+0000'格式
Args:
date_str: 'YYYY-MM-DD HH:MM:SS'格式的日期字符串
Returns:
转换后的API格式日期字符串
"""
if not date_str:
return None
try:
# 解析输入的日期字符串为datetime对象假设为本地时间
local_tz = pytz.timezone('Asia/Shanghai')
# 尝试解析不同格式
try:
# 带时间的完整格式
dt = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
except ValueError:
try:
# 仅日期格式
dt = datetime.strptime(date_str, "%Y-%m-%d")
except ValueError:
# 如果已经是ISO格式直接返回
if 'T' in date_str:
return date_str
# 其他格式无法解析
return date_str
# 将解析的datetime转换为本地时区的datetime
dt = local_tz.localize(dt)
# 转换为UTC时间
utc_dt = dt.astimezone(pytz.UTC)
# 格式化为API需要的格式YYYY-MM-DDThh:mm:ss.000+0000
return utc_dt.strftime("%Y-%m-%dT%H:%M:%S.000+0000")
except Exception as e:
# 日期格式转换错误禁用print避免干扰JSONRPC
pass
return date_str
def _simplify_task_data(task_data: Dict[str, Any], projects_data: List[Dict[str, Any]] = None) -> Dict[str, Any]:
"""简化任务数据,保留重要字段并格式化日期"""
# 格式化日期函数
def format_date(date_str, is_due_date=False):
if not date_str:
return None
dt = _parse_date(date_str)
if not dt:
return date_str
# 如果是截止日期且时间是0点考虑添加一天
if is_due_date and dt.hour == 0 and dt.minute == 0 and dt.second == 0:
dt = dt + timedelta(days=1)
return dt.strftime("%Y-%m-%d %H:%M:%S")
# 如果提供了项目数据列表且当前任务只有projectId但没有projectName则匹配项目名称
if projects_data and task_data.get('projectId') and not task_data.get('projectName'):
task_data = _merge_project_info_logic(task_data, projects_data)
# 处理子任务
children = []
if task_data.get('items'):
for item in task_data['items']:
# 递归调用,同时传递项目数据
child_task = _simplify_task_data(item, projects_data)
children.append(child_task)
# 创建基础任务数据
simplified = {
"id": task_data.get("id"),
"title": task_data.get("title"),
"content": task_data.get("content"),
"priority": task_data.get("priority"),
"status": task_data.get("status"),
"completed": task_data.get("isCompleted", False),
"projectId": task_data.get("projectId"),
"projectName": task_data.get("projectName", "默认清单"),
"projectKind": task_data.get("projectKind"),
"columnId": task_data.get("columnId"),
"tags": task_data.get("tags", []),
"tagDetails": task_data.get("tagDetails", []),
"startDate": format_date(task_data.get("startDate")),
"dueDate": format_date(task_data.get("dueDate"), is_due_date=True),
"completedTime": format_date(task_data.get("completedTime")),
"createdTime": format_date(task_data.get("createdTime")),
"modifiedTime": format_date(task_data.get("modifiedTime")),
"isAllDay": task_data.get("isAllDay", False),
"reminder": task_data.get("reminder"),
"progress": task_data.get("progress", 0),
"kind": task_data.get("kind"),
"isCompleted": task_data.get("isCompleted", False),
"items": children,
"timeZone": "Asia/Shanghai",
"reminders": task_data.get("reminders", []),
"creator": task_data.get("creator"),
"sortOrder": task_data.get("sortOrder", 0),
"parentId": task_data.get("parentId"),
"children": children
}
# 移除None值
simplified = {k: v for k, v in simplified.items() if v is not None}
return simplified
def _get_completed_tasks_info_logic() -> Dict[str, Any]:
"""(已废弃路径) 兼容占位官方API不提供旧批量接口返回空。"""
return {}
def _update_column_info_logic(projects: List[Dict[str, Any]], completed_columns_set: set):
"""更新栏目信息,识别已完成状态的栏目 (逻辑部分)"""
for project in projects:
if 'columns' in project:
for column in project.get('columns', []):
# 检查栏目是否为已完成状态
if column.get('type') == 'COMPLETED':
completed_columns_set.add(column.get('id'))
def _merge_project_info_logic(task_data: Dict[str, Any], projects: List[Dict[str, Any]]) -> Dict[str, Any]:
"""将项目信息合并到任务数据中 (逻辑部分)"""
if not task_data.get('projectId'):
return task_data
for project in projects:
if project.get('id') == task_data['projectId']:
task_data['projectName'] = project.get('name')
task_data['projectKind'] = project.get('kind')
break
return task_data
def _merge_tag_info_logic(task_data: Dict[str, Any], tags: List[Dict[str, Any]]) -> Dict[str, Any]:
"""将标签详细信息合并到任务数据中 (逻辑部分)"""
if not task_data.get('tags'):
return task_data
tag_details = []
for tag_name in task_data['tags']:
for tag in tags:
if tag.get('name') == tag_name:
tag_details.append({
'name': tag.get('name'),
'label': tag.get('label')
})
break
task_data['tagDetails'] = tag_details
return task_data
def _get_all_tasks_logic() -> tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[Dict[str, Any]]]:
"""获取所有任务,包括已完成和未完成的任务,并合并相关信息 (逻辑部分)"""
global _completed_columns
# 使用官方接口获取项目与任务
projects_data = []
try:
projects_data = adapter.list_projects()
except Exception:
projects_data = []
# 官方任务接口通常需要分别获取未完成/已完成,视文档具体筛选实现
tasks_data: List[Dict[str, Any]] = []
tags_data: List[Dict[str, Any]] = [] # 若官方没有标签API则保留空集合
try:
# 遍历项目聚合任务(官方无全局列表端点)
incomplete = adapter.list_tasks(completed=False)
complete = adapter.list_tasks(completed=True)
tasks_data = (incomplete or []) + (complete or [])
except Exception as e:
# 获取任务列表失败禁用print避免干扰JSONRPC
pass
tasks_data = []
# 更新栏目信息 (使用全局变量)
_update_column_info_logic(projects_data, _completed_columns)
# 旧逻辑依赖批量端点合并“已完成”,现在已通过 adapter 分开获取,这里置空
completed_tasks_info = {}
# 处理所有任务(未完成+已完成)
all_tasks = []
# 处理未完成任务
for task in tasks_data:
# 只处理文本类型的任务
if task.get('kind') != 'TEXT':
continue
# 合并项目和标签信息
task = _merge_project_info_logic(task, projects_data)
task = _merge_tag_info_logic(task, tags_data)
# 检查是否在已完成任务列表中
key = f"{task.get('creator')}_{task.get('title')}"
# adapter.normalize_task_status 已处理 isCompleted/status这里不再强制覆盖
all_tasks.append(task)
# 不再需要从已完成任务列表补充adapter 已统一返回
return all_tasks, projects_data, tags_data
# --- 模块级核心逻辑函数 ---
def get_tasks_logic(
mode: Optional[str] = "all",
keyword: Optional[str] = None,
priority: Optional[int] = None,
project_name: Optional[str] = None,
completed: Optional[bool] = None
) -> List[Dict[str, Any]]:
"""
获取任务列表 (逻辑部分)
Args:
mode: 任务模式支持 'all'(所有), 'today'(今天), 'yesterday'(昨天), 'recent_7_days'(最近7天)
keyword: 关键词筛选
priority: 优先级筛选 (0-最低, 1-, 3-, 5-)
project_name: 项目名称筛选
completed: 是否已完成True表示已完成False表示未完成None表示全部
Returns:
符合条件的任务列表
"""
try:
# 如果是查询今天的任务,默认只显示未完成的任务
if mode == "today" and completed is None:
completed = False
# 获取所有任务
all_tasks, projects_data, tags_data = _get_all_tasks_logic()
# 确保所有任务都有正确的project_name (在过滤之前)
for task in all_tasks:
if task.get('projectId') and not task.get('projectName'):
_merge_project_info_logic(task, projects_data)
def is_today(task):
# 检查任务是否为今天
local_tz = pytz.timezone('Asia/Shanghai')
now = datetime.now(local_tz)
today = now.date()
# 解析日期并获取日期部分
start_date = _parse_date(task.get('startDate'))
due_date = _parse_date(task.get('dueDate'))
# 简化判断逻辑:使用截止日期或开始日期判断
task_date = due_date or start_date
# 判断日期是否为今天
if task_date and task_date.date() == today:
return True
# 如果任务跨越今天(开始日期在今天之前,截止日期在今天之后或无截止日期)
if start_date and start_date.date() < today:
if not due_date or due_date.date() >= today:
return True
return False
def is_yesterday(task):
# 检查任务是否为昨天
local_tz = pytz.timezone('Asia/Shanghai')
now = datetime.now(local_tz)
yesterday = (now - timedelta(days=1)).date()
# 解析日期
start_date = _parse_date(task.get('startDate'))
due_date = _parse_date(task.get('dueDate'))
# 简化判断逻辑:使用截止日期或开始日期判断
task_date = due_date or start_date
return task_date and task_date.date() == yesterday
def is_recent_7_days(task):
# 检查任务是否属于最近7天
local_tz = pytz.timezone('Asia/Shanghai')
now = datetime.now(local_tz)
seven_days_ago = (now - timedelta(days=7))
# 解析日期
start_date = _parse_date(task.get('startDate'))
due_date = _parse_date(task.get('dueDate'))
# 简化判断逻辑:使用截止日期或开始日期判断
task_date = due_date or start_date
# 最近7天的任务
if task_date and task_date >= seven_days_ago:
return True
# 跨越这7天的任务
if start_date and start_date < seven_days_ago:
if due_date and due_date >= seven_days_ago:
return True
return False
# 过滤任务
result = []
for task in all_tasks:
# 根据完成状态筛选
if completed is not None:
is_task_completed = task.get('isCompleted', False)
if is_task_completed != completed:
continue
# 根据模式筛选
if mode == "today" and not is_today(task):
continue
elif mode == "yesterday" and not is_yesterday(task):
continue
elif mode == "recent_7_days" and not is_recent_7_days(task):
continue
# 根据其他条件筛选
if keyword and keyword.lower() not in task.get('title', '').lower() and keyword.lower() not in task.get('content', '').lower():
continue
if priority is not None and task.get('priority') != priority:
continue
# 根据项目名称筛选 (现在任务已经有了正确的project_name)
if project_name and project_name not in task.get('projectName', ''):
continue
# 保留简化后的任务数据,传递项目数据
simplified_task = _simplify_task_data(task, projects_data)
result.append(simplified_task)
return result
except Exception as e:
# 获取任务列表时发生错误禁用print避免干扰JSONRPC
pass
return []
def create_task_logic(
title: Optional[str] = None,
content: Optional[str] = None,
priority: Optional[int] = None,
project_name: Optional[str] = None,
tag_names: Optional[List[str]] = None,
start_date: Optional[str] = None,
due_date: Optional[str] = None,
is_all_day: Optional[bool] = None,
reminder: Optional[str] = None,
kind: Optional[str] = None,
# 官方字段(新增)
project_id: Optional[str] = None,
desc: Optional[str] = None,
time_zone: Optional[str] = None,
reminders: Optional[List[str]] = None,
repeat_flag: Optional[str] = None,
sort_order: Optional[int] = None,
items: Optional[List[Dict[str, Any]]] = None
) -> Dict[str, Any]:
"""
创建新任务 (逻辑部分)
Args:
title: 任务标题
content: 任务内容
priority: 优先级 (0-最低, 1-, 3-, 5-)
project_name: 项目名称
tag_names: 标签名称列表
start_date: 开始日期格式 'YYYY-MM-DD HH:MM:SS'
due_date: 截止日期格式 'YYYY-MM-DD HH:MM:SS'
is_all_day: 是否为全天任务
reminder: 提醒选项 "0"(准时), "-5M"(提前5分钟), "-1H"(提前1小时), "-1D"(提前1天)
Returns:
创建的任务信息
"""
resolved_project_id = project_id
projects_data = adapter.list_projects()
if not resolved_project_id and project_name:
# 尝试精确匹配
for project in projects_data:
if project.get('name') == project_name:
resolved_project_id = project.get('id')
break
# 如果精确匹配失败,尝试不区分大小写的匹配
if not resolved_project_id and project_name:
project_name_lower = project_name.lower()
for project in projects_data:
if project.get('name', '').lower() == project_name_lower:
# 不区分大小写匹配到项目禁用print避免干扰JSONRPC
pass
resolved_project_id = project.get('id')
break
# 如果仍然失败,尝试部分匹配
if not resolved_project_id and project_name:
for project in projects_data:
if project_name.lower() in project.get('name', '').lower() or project.get('name', '').lower() in project_name.lower():
# 部分匹配到项目禁用print避免干扰JSONRPC
pass
resolved_project_id = project.get('id')
break
# 准备任务数据
task_data = {
"title": title,
"content": content,
"priority": priority,
"projectId": resolved_project_id,
# 官方任务未公开 tags 字段,保留为兼容逻辑但不强制发送
# "tags": tag_names or [],
"isAllDay": is_all_day,
"reminder": reminder,
"status": 0,
"kind": kind,
# 官方字段
"desc": desc,
"timeZone": time_zone,
"reminders": reminders,
"repeatFlag": repeat_flag,
"sortOrder": sort_order,
"items": items,
}
# 处理日期和提醒
if start_date:
# 转换为API所需的格式
task_data["startDate"] = _format_date_for_api(start_date)
if due_date:
# 转换为API所需的格式
task_data["dueDate"] = _format_date_for_api(due_date)
if reminder:
task_data["reminder"] = reminder
# 移除None值的字段
task_data = {k: v for k, v in task_data.items() if v is not None}
# Debug: task_data (禁用print以避免干扰JSONRPC)
# 发送创建请求
response = adapter.create_task(task_data)
# 返回简化后的响应,同时传递项目数据
return _simplify_task_data(response, projects_data)
def update_task_logic(
task_id_or_title: str,
title: Optional[str] = None,
content: Optional[str] = None,
priority: Optional[int] = None,
project_name: Optional[str] = None,
tag_names: Optional[List[str]] = None,
start_date: Optional[str] = None,
due_date: Optional[str] = None,
is_all_day: Optional[bool] = None,
reminder: Optional[str] = None,
status: Optional[int] = None,
# 官方字段(新增)
project_id: Optional[str] = None,
desc: Optional[str] = None,
time_zone: Optional[str] = None,
reminders: Optional[List[str]] = None,
repeat_flag: Optional[str] = None,
sort_order: Optional[int] = None,
items: Optional[List[Dict[str, Any]]] = None
) -> Dict[str, Any]:
"""
更新任务 (逻辑部分)
Args:
task_id_or_title: 任务ID或任务标题
title: 新任务标题
content: 新任务内容
priority: 新优先级 (0-最低, 1-, 3-, 5-)
project_name: 新项目名称
tag_names: 新标签名称列表
start_date: 新开始日期格式 'YYYY-MM-DD HH:MM:SS'
due_date: 新截止日期格式 'YYYY-MM-DD HH:MM:SS'
is_all_day: 是否为全天任务
reminder: 新提醒选项
status: 新状态0表示未完成2表示已完成
Returns:
更新后的任务信息字典 (包含 success, info, data)
"""
try:
# 获取所有任务
all_tasks, projects_data, _ = _get_all_tasks_logic()
# 查找任务
task = None
# 先尝试按ID查找
for t in all_tasks:
if t.get('id') == task_id_or_title:
task = t
break
# 如果没找到,按标题查找
if not task:
for t in all_tasks:
if t.get('title') == task_id_or_title:
task = t
break
if not task:
return {
"success": False,
"info": f"未找到ID或标题为 '{task_id_or_title}' 的任务",
"data": None
}
task_id = task.get('id')
# 查找项目ID如果指定了项目名称
project_id = project_id or task.get('projectId')
if project_name and not project_id:
for project in projects_data:
if project.get('name') == project_name:
project_id = project.get('id')
break
# 准备更新数据
update_data = {
"id": task_id,
"title": title if title is not None else task.get('title'),
"content": content if content is not None else task.get('content'),
"priority": priority if priority is not None else task.get('priority'),
"projectId": project_id,
# 官方未公开 tags 写入,去除发送
"isAllDay": is_all_day if is_all_day is not None else task.get('isAllDay'),
"status": status if status is not None else task.get('status'),
# 官方字段
"desc": desc if desc is not None else task.get('desc'),
"timeZone": time_zone if time_zone is not None else task.get('timeZone'),
"reminders": reminders if reminders is not None else task.get('reminders'),
"repeatFlag": repeat_flag if repeat_flag is not None else task.get('repeatFlag'),
"sortOrder": sort_order if sort_order is not None else task.get('sortOrder'),
"items": items if items is not None else task.get('items'),
}
# 处理日期和提醒
if start_date is not None:
# 转换为API所需的格式
update_data["startDate"] = _format_date_for_api(start_date)
elif 'startDate' in task:
update_data["startDate"] = task['startDate']
if due_date is not None:
# 转换为API所需的格式
update_data["dueDate"] = _format_date_for_api(due_date)
elif 'dueDate' in task:
update_data["dueDate"] = task['dueDate']
if reminder is not None:
update_data["reminder"] = reminder
elif 'reminder' in task:
update_data["reminder"] = task['reminder']
# 移除None值的字段
update_data = {k: v for k, v in update_data.items() if v is not None}
# 状态变更:对齐官方逻辑(仅支持完成)
if status is not None:
if status == 2:
if not project_id:
return {
"success": False,
"info": "完成任务失败:缺少 projectId",
"data": None
}
try:
adapter.complete_task(project_id, task_id)
# 完成后刷新一次该项目任务,返回最新数据
refreshed = adapter.list_tasks(project_id=project_id)
fresh = next((t for t in refreshed if t.get('id') == task_id), None)
if fresh:
return {
"success": True,
"info": "任务已完成",
"data": _simplify_task_data(fresh, projects_data)
}
except Exception as e:
return {
"success": False,
"info": f"完成任务失败: {e}",
"data": None
}
# 若无法刷新,基于原任务构造完成态返回
task_after = dict(task)
task_after['status'] = 2
task_after['isCompleted'] = True
return {
"success": True,
"info": "任务已完成",
"data": _simplify_task_data(task_after, projects_data)
}
elif status == 0:
return {
"success": False,
"info": "取消完成未在官方开放API中提供暂不支持",
"data": None
}
# 非状态变更:走常规更新
# Debug: 更新数据禁用print避免干扰JSONRPC
pass
response = adapter.update_task(task_id, update_data)
# 返回更新结果
return {
"success": True,
"info": "任务更新成功",
"data": _simplify_task_data(response, projects_data)
}
except Exception as e:
# 更新任务失败禁用print避免干扰JSONRPC
return {
"success": False,
"info": f"更新任务失败: {str(e)}",
"data": None
}
def delete_task_logic(task_id_or_title: str) -> Dict[str, Any]:
"""
删除任务 (逻辑部分)
Args:
task_id_or_title: 任务ID或任务标题
Returns:
删除操作的响应字典 (包含 success, info, data)
"""
try:
# 获取所有任务
all_tasks, projects_data, _ = _get_all_tasks_logic()
task = None
# 先尝试按ID查找
for t in all_tasks:
if t.get('id') == task_id_or_title:
task = t
break
# 如果没找到,按标题查找
if not task:
for t in all_tasks:
if t.get('title') == task_id_or_title:
task = t
break
if not task:
return {
"success": False,
"info": f"未找到ID或标题为 '{task_id_or_title}' 的任务",
"data": None
}
task_id = task.get('id')
project_id = task.get('projectId')
# 发送删除请求
# 官方删除需要 projectId
adapter.delete_task(project_id, task_id)
# 返回删除结果
return {
"success": True,
"info": f"成功删除任务 '{task.get('title')}'",
"data": _simplify_task_data(task, projects_data)
}
except Exception as e:
# 删除任务失败禁用print避免干扰JSONRPC
return {
"success": False,
"info": f"删除任务失败: {str(e)}",
"data": None
}
def complete_task_logic(task_id_or_title: str) -> Dict[str, Any]:
"""
完成任务调用官方 complete 接口
Args:
task_id_or_title: 任务ID或任务标题
Returns:
操作结果字典
"""
try:
all_tasks, projects_data, _ = _get_all_tasks_logic()
task = None
for t in all_tasks:
if t.get('id') == task_id_or_title or t.get('title') == task_id_or_title:
task = t
break
if not task:
return {
"success": False,
"info": f"未找到ID或标题为 '{task_id_or_title}' 的任务",
"data": None
}
task_id = task.get('id')
project_id = task.get('projectId')
if not project_id:
return {
"success": False,
"info": "完成任务失败:缺少 projectId",
"data": None
}
adapter.complete_task(project_id, task_id)
# 刷新该项目任务,返回最新数据
refreshed = adapter.list_tasks(project_id=project_id)
fresh = next((t for t in refreshed if t.get('id') == task_id), None)
if fresh:
return {
"success": True,
"info": "任务已完成",
"data": _simplify_task_data(fresh, projects_data)
}
# 无法刷新则回退构造
task_after = dict(task)
task_after['status'] = 2
task_after['isCompleted'] = True
return {
"success": True,
"info": "任务已完成",
"data": _simplify_task_data(task_after, projects_data)
}
except Exception as e:
return {
"success": False,
"info": f"完成任务失败: {e}",
"data": None
}
# --- MCP工具注册 ---
def register_task_tools(server: FastMCP, auth_info: Dict[str, Any]):
"""
注册任务相关工具到MCP服务器
Args:
server: MCP服务器实例
auth_info: 认证信息字典包含token或email/password
"""
# 适配层按需初始化,无需在此显式初始化
@server.tool()
def get_tasks(
mode: Optional[str] = "all",
keyword: Optional[str] = None,
priority: Optional[int] = None,
project_name: Optional[str] = None,
completed: Optional[bool] = None
) -> List[Dict[str, Any]]:
"""
获取任务列表
(调用模块级逻辑函数)
Args:
mode: 任务模式支持 'all'(所有), 'today'(今天), 'yesterday'(昨天), 'recent_7_days'(最近7天)
keyword: 关键词筛选
priority: 优先级筛选 (0-最低, 1-, 3-, 5-)
project_name: 项目名称筛选
completed: 是否已完成True表示已完成False表示未完成None表示全部
Returns:
符合条件的任务列表
"""
return get_tasks_logic(mode=mode, keyword=keyword, priority=priority, project_name=project_name, completed=completed)
@server.tool()
def create_task(
title: Optional[str] = None,
content: Optional[str] = None,
priority: Optional[int] = None,
project_name: Optional[str] = None,
tag_names: Optional[List[str]] = None,
start_date: Optional[str] = None,
due_date: Optional[str] = None,
is_all_day: Optional[bool] = None,
reminder: Optional[str] = None,
# 官方字段(新增)
project_id: Optional[str] = None,
desc: Optional[str] = None,
time_zone: Optional[str] = None,
reminders: Optional[List[str]] = None,
repeat_flag: Optional[str] = None,
sort_order: Optional[int] = None,
items: Optional[List[Dict[str, Any]]] = None
) -> Dict[str, Any]:
"""
创建新任务
(调用模块级逻辑函数)
Args:
title: 任务标题
content: 任务内容
priority: 优先级 (0-最低, 1-, 3-, 5-)
project_name: 项目名称
tag_names: 标签名称列表
start_date: 开始日期格式 'YYYY-MM-DD HH:MM:SS'会自动转换为API所需的时区和格式
due_date: 截止日期格式 'YYYY-MM-DD HH:MM:SS'会自动转换为API所需的时区和格式
is_all_day: 是否为全天任务
reminder: 提醒选项 "0"(准时), "-5M"(提前5分钟), "-1H"(提前1小时), "-1D"(提前1天)
Returns:
创建的任务信息
"""
return create_task_logic(title=title, content=content, priority=priority, project_name=project_name, tag_names=tag_names, start_date=start_date, due_date=due_date, is_all_day=is_all_day, reminder=reminder, project_id=project_id, desc=desc, time_zone=time_zone, reminders=reminders, repeat_flag=repeat_flag, sort_order=sort_order, items=items)
@server.tool()
def update_task(
task_id_or_title: str,
title: Optional[str] = None,
content: Optional[str] = None,
priority: Optional[int] = None,
project_name: Optional[str] = None,
tag_names: Optional[List[str]] = None,
start_date: Optional[str] = None,
due_date: Optional[str] = None,
is_all_day: Optional[bool] = None,
reminder: Optional[str] = None,
status: Optional[int] = None
) -> Dict[str, Any]:
"""
更新任务
(调用模块级逻辑函数)
Args:
task_id_or_title: 任务ID或任务标题
title: 新任务标题
content: 新任务内容
priority: 新优先级 (0-最低, 1-, 3-, 5-)
project_name: 新项目名称
tag_names: 新标签名称列表
start_date: 新开始日期格式 'YYYY-MM-DD HH:MM:SS'会自动转换为API所需的时区和格式
due_date: 新截止日期格式 'YYYY-MM-DD HH:MM:SS'会自动转换为API所需的时区和格式
is_all_day: 是否为全天任务
reminder: 新提醒选项
status: 新状态0表示未完成2表示已完成
Returns:
更新后的任务信息
"""
return update_task_logic(task_id_or_title=task_id_or_title, title=title, content=content, priority=priority, project_name=project_name, tag_names=tag_names, start_date=start_date, due_date=due_date, is_all_day=is_all_day, reminder=reminder, status=status)
@server.tool()
def delete_task(task_id_or_title: str) -> Dict[str, Any]:
"""
删除任务
(调用模块级逻辑函数)
Args:
task_id_or_title: 任务ID或任务标题
Returns:
删除操作的响应
"""
return delete_task_logic(task_id_or_title=task_id_or_title)
@server.tool()
def complete_task(task_id_or_title: str) -> Dict[str, Any]:
"""
完成任务官方POST /open/v1/project/{projectId}/task/{taskId}/complete
Args:
task_id_or_title: 任务ID或任务标题
Returns:
操作结果
"""
return complete_task_logic(task_id_or_title)
# 导出可供外部引用的函数
__all__ = [
'get_tasks_logic',
'create_task_logic',
'update_task_logic',
'delete_task_logic',
'complete_task_logic',
'register_task_tools',
'_get_all_tasks_logic' # 如果需要外部访问
]