You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
7.8 KiB
230 lines
7.8 KiB
"""任务管理工具模块。
|
|
|
|
提供任务相关操作的封装,包括任务列表查询、创建、获取详情、更新状态等功能。
|
|
通过内部 HTTP API 与后端任务服务通信,使用 JWT 服务令牌进行认证。
|
|
"""
|
|
import httpx
|
|
import logging
|
|
import os
|
|
import jwt
|
|
import time
|
|
from config import settings
|
|
|
|
logger = logging.getLogger(__name__) # 当前模块的日志记录器
|
|
|
|
_INTERNAL_BASE = os.getenv("INTERNAL_API_BASE", "http://127.0.0.1:8000/api") # 内部 API 基础地址
|
|
_client: httpx.Client | None = None # 全局复用的 HTTP 客户端实例
|
|
|
|
|
|
def _get_client() -> httpx.Client:
|
|
"""获取或创建全局复用的 HTTP 客户端实例。
|
|
|
|
Returns:
|
|
httpx.Client: 配置了超时时间的 HTTP 客户端。
|
|
"""
|
|
global _client
|
|
if _client is None:
|
|
_client = httpx.Client(timeout=30)
|
|
return _client
|
|
|
|
|
|
def _get_service_token() -> str | None:
|
|
"""生成用于内部服务间调用的 JWT 令牌。
|
|
|
|
Returns:
|
|
str | None: 编码后的 JWT 令牌,生成失败返回 None。
|
|
"""
|
|
try:
|
|
payload = {
|
|
"sub": "system_tool", # 令牌主体标识为系统工具
|
|
"exp": int(time.time()) + 3600, # 1 小时后过期
|
|
"type": "service", # 令牌类型为服务令牌
|
|
}
|
|
token = jwt.encode(payload, settings.JWT_SECRET, algorithm="HS256")
|
|
return token
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def _headers(token: str | None = None) -> dict:
|
|
"""构建 HTTP 请求头,包含认证令牌。
|
|
|
|
Args:
|
|
token: 可选的自定义令牌,不提供则自动生成服务令牌。
|
|
|
|
Returns:
|
|
dict: 包含 Authorization 头的字典。
|
|
"""
|
|
t = token or _get_service_token()
|
|
return {"Authorization": f"Bearer {t}"} if t else {}
|
|
|
|
|
|
# 工具函数描述 Schema,用于 AgentScope 工具注册
|
|
SCHEMAS = {
|
|
"list_tasks": {
|
|
"name": "list_tasks",
|
|
"description": "查询任务列表,可选按状态筛选",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"status": {"type": "string", "description": "任务状态筛选", "enum": ["todo", "in_progress", "done"]}
|
|
}
|
|
}
|
|
},
|
|
"create_task": {
|
|
"name": "create_task",
|
|
"description": "创建新任务",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"title": {"type": "string", "description": "任务标题"},
|
|
"description": {"type": "string", "description": "任务描述"},
|
|
"assignee_id": {"type": "string", "description": "负责人ID"},
|
|
"priority": {"type": "string", "description": "优先级", "enum": ["low", "medium", "high", "urgent"]},
|
|
"deadline": {"type": "string", "description": "截止日期"}
|
|
},
|
|
"required": ["title"]
|
|
}
|
|
},
|
|
"get_task": {
|
|
"name": "get_task",
|
|
"description": "查询指定任务详情",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {"task_id": {"type": "string", "description": "任务ID"}},
|
|
"required": ["task_id"]
|
|
}
|
|
},
|
|
"update_task": {
|
|
"name": "update_task",
|
|
"description": "更新任务状态或描述",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"task_id": {"type": "string", "description": "任务ID"},
|
|
"status": {"type": "string", "description": "新状态", "enum": ["todo", "in_progress", "done"]},
|
|
"description": {"type": "string", "description": "新描述"}
|
|
},
|
|
"required": ["task_id"]
|
|
}
|
|
},
|
|
"push_task_to_wecom": {
|
|
"name": "push_task_to_wecom",
|
|
"description": "将任务推送到企业微信",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {"task_id": {"type": "string", "description": "任务ID"}},
|
|
"required": ["task_id"]
|
|
}
|
|
},
|
|
}
|
|
|
|
|
|
def list_tasks(status: str | None = None) -> str:
|
|
"""查询任务列表,支持按状态筛选。
|
|
|
|
Args:
|
|
status: 可选的任务状态筛选条件(todo/in_progress/done)。
|
|
|
|
Returns:
|
|
str: 格式化的任务列表文本或错误信息。
|
|
"""
|
|
try:
|
|
resp = _get_client().get(f"{_INTERNAL_BASE}/tasks", headers=_headers())
|
|
tasks = resp.json() if isinstance(resp.json(), list) else resp.json().get("data", [])
|
|
if status:
|
|
tasks = [t for t in tasks if t.get("status") == status]
|
|
if not tasks:
|
|
return "当前没有任务。"
|
|
lines = []
|
|
for t in tasks:
|
|
lines.append(
|
|
f"- [{t.get('status', '?')}] {t.get('id', '')[:8]} | {t.get('title', '无标题')} "
|
|
f"| 负责人: {t.get('assignee_name', t.get('assignee_id', '无人'))} "
|
|
f"| 截止: {t.get('deadline', '无')} "
|
|
f"| 优先级: {t.get('priority', '?')}"
|
|
)
|
|
return "\n".join(lines)
|
|
except Exception as e:
|
|
return f"查询任务列表失败: {e}"
|
|
|
|
|
|
def create_task(title: str, description: str = "", assignee_id: str = "", priority: str = "medium", deadline: str | None = None) -> str:
|
|
"""创建新任务。
|
|
|
|
Args:
|
|
title: 任务标题(必填)。
|
|
description: 任务描述。
|
|
assignee_id: 负责人用户 ID。
|
|
priority: 任务优先级,默认 medium。
|
|
deadline: 截止日期。
|
|
|
|
Returns:
|
|
str: 创建结果描述或错误信息。
|
|
"""
|
|
try:
|
|
body = {"title": title, "description": description, "assignee_id": assignee_id, "priority": priority, "deadline": deadline}
|
|
resp = _get_client().post(f"{_INTERNAL_BASE}/tasks", json=body, headers=_headers())
|
|
task = resp.json()
|
|
return f"任务创建成功: {task.get('title', title)} (ID: {task.get('id', '?')[:8]})"
|
|
except Exception as e:
|
|
return f"创建任务失败: {e}"
|
|
|
|
|
|
def get_task(task_id: str) -> str:
|
|
"""查询指定任务的详细信息。
|
|
|
|
Args:
|
|
task_id: 任务唯一标识 ID。
|
|
|
|
Returns:
|
|
str: 格式化的任务详情文本或错误信息。
|
|
"""
|
|
try:
|
|
resp = _get_client().get(f"{_INTERNAL_BASE}/tasks/{task_id}", headers=_headers())
|
|
t = resp.json()
|
|
return f"任务: {t.get('title', '?')}\n描述: {t.get('description', '无')}\n负责人: {t.get('assignee_name', t.get('assignee_id', '无人'))}\n状态: {t.get('status', '?')} | 优先级: {t.get('priority', '?')} | 截止: {t.get('deadline', '无')}"
|
|
except Exception as e:
|
|
return f"查询任务失败: {e}"
|
|
|
|
|
|
def update_task(task_id: str, status: str | None = None, description: str | None = None) -> str:
|
|
"""更新任务状态或描述。
|
|
|
|
Args:
|
|
task_id: 任务唯一标识 ID。
|
|
status: 新的任务状态(todo/in_progress/done)。
|
|
description: 新的任务描述。
|
|
|
|
Returns:
|
|
str: 更新结果描述或错误信息。
|
|
"""
|
|
try:
|
|
body = {}
|
|
if status:
|
|
body["status"] = status
|
|
if description:
|
|
body["description"] = description
|
|
resp = _get_client().put(f"{_INTERNAL_BASE}/tasks/{task_id}", json=body, headers=_headers())
|
|
return f"任务 {task_id[:8]} 已更新"
|
|
except Exception as e:
|
|
return f"更新任务失败: {e}"
|
|
|
|
|
|
def push_task_to_wecom(task_id: str) -> str:
|
|
"""将任务通知推送到企业微信。
|
|
|
|
Args:
|
|
task_id: 任务唯一标识 ID。
|
|
|
|
Returns:
|
|
str: 推送结果描述或错误信息。
|
|
"""
|
|
try:
|
|
resp = _get_client().post(f"{_INTERNAL_BASE}/tasks/{task_id}/push", headers=_headers())
|
|
return f"任务 {task_id[:8]} 已推送至企业微信"
|
|
except Exception as e:
|
|
return f"推送任务失败: {e}"
|
|
|
|
|
|
__all__ = ["list_tasks", "create_task", "get_task", "update_task", "push_task_to_wecom", "SCHEMAS"]
|
|
|