feat: 添加任务调度器、后台任务运行器及多种工具支持
实现后台任务调度器(scheduler.py)和任务运行器(task_runner.py),支持长时间运行任务的异步执行和状态跟踪 新增多种工具支持:Shell命令执行、文件操作(读写/搜索/发送)、网页搜索/问答、定时提醒等 扩展README和ROADMAP文档,描述新功能和未来多主机架构规划 在配置文件中添加METASO_API_KEY支持秘塔AI搜索功能 优化代理逻辑,自动识别通用问题直接回答而不创建会话
This commit is contained in:
+79
-1
@@ -10,8 +10,10 @@ import uuid
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from agent.manager import manager
|
||||
from agent.scheduler import scheduler
|
||||
from agent.task_runner import task_runner
|
||||
from orchestrator.agent import agent
|
||||
from orchestrator.tools import set_current_user, get_current_user
|
||||
from orchestrator.tools import set_current_user, get_current_user, get_current_chat
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -59,6 +61,12 @@ async def handle_command(user_id: str, text: str) -> Optional[str]:
|
||||
return _cmd_direct(user_id)
|
||||
elif cmd == "/smart":
|
||||
return _cmd_smart(user_id)
|
||||
elif cmd == "/tasks":
|
||||
return _cmd_tasks()
|
||||
elif cmd == "/shell":
|
||||
return await _cmd_shell(args)
|
||||
elif cmd == "/remind":
|
||||
return await _cmd_remind(args)
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -203,6 +211,73 @@ def _cmd_smart(user_id: str) -> str:
|
||||
return "✓ Smart mode ON. Messages go through LLM for intelligent routing."
|
||||
|
||||
|
||||
def _cmd_tasks() -> str:
|
||||
"""List background tasks."""
|
||||
tasks = task_runner.list_tasks()
|
||||
if not tasks:
|
||||
return "No background tasks."
|
||||
|
||||
lines = ["**Background Tasks:**\n"]
|
||||
for t in tasks:
|
||||
status_emoji = {"completed": "✅", "failed": "❌", "running": "⏳", "pending": "⏸️"}.get(
|
||||
t["status"], "❓"
|
||||
)
|
||||
lines.append(f"{status_emoji} #{t['task_id']} - {t['description'][:50]} ({t['elapsed']}s)")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
async def _cmd_shell(args: str) -> str:
|
||||
"""Execute a shell command directly."""
|
||||
if not args:
|
||||
return "Usage: /shell <command>\nExample: /shell git status"
|
||||
|
||||
from orchestrator.tools import ShellTool, get_current_chat
|
||||
|
||||
tool = ShellTool()
|
||||
result = await tool._arun(command=args)
|
||||
try:
|
||||
data = json.loads(result)
|
||||
if "error" in data:
|
||||
return f"❌ {data['error']}"
|
||||
output = []
|
||||
if data.get("stdout"):
|
||||
output.append(data["stdout"])
|
||||
if data.get("stderr"):
|
||||
output.append(f"[stderr] {data['stderr']}")
|
||||
output.append(f"[exit code: {data.get('exit_code', '?')}]")
|
||||
return "\n".join(output) if output else "(no output)"
|
||||
except json.JSONDecodeError:
|
||||
return result
|
||||
|
||||
|
||||
async def _cmd_remind(args: str) -> str:
|
||||
"""Set a reminder."""
|
||||
if not args:
|
||||
return "Usage: /remind <time> <message>\nExample: /remind 10m check the build\nTime format: 30s, 10m, 1h"
|
||||
|
||||
parts = args.split(None, 1)
|
||||
if len(parts) < 2:
|
||||
return "Usage: /remind <time> <message>\nExample: /remind 10m check the build"
|
||||
|
||||
time_str, message = parts
|
||||
match = re.match(r'^(\d+)(s|m|h)$', time_str.lower())
|
||||
if not match:
|
||||
return "Invalid time format. Use: 30s, 10m, 1h"
|
||||
|
||||
value = int(match.group(1))
|
||||
unit = match.group(2)
|
||||
seconds = value * {'s': 1, 'm': 60, 'h': 3600}[unit]
|
||||
|
||||
chat_id = get_current_chat()
|
||||
job_id = await scheduler.schedule_once(
|
||||
delay_seconds=seconds,
|
||||
message=message,
|
||||
notify_chat_id=chat_id,
|
||||
)
|
||||
|
||||
return f"⏰ Reminder #{job_id} set for {value}{unit} from now"
|
||||
|
||||
|
||||
def _cmd_help() -> str:
|
||||
"""Show help."""
|
||||
return """**Commands:**
|
||||
@@ -212,5 +287,8 @@ def _cmd_help() -> str:
|
||||
/switch <n> - Switch to session by number
|
||||
/direct - Direct mode: messages → Claude Code (no LLM overhead)
|
||||
/smart - Smart mode: messages → LLM routing (default)
|
||||
/shell <cmd> - Run shell command (bypasses LLM)
|
||||
/remind <time> <msg> - Set reminder (e.g. /remind 10m check build)
|
||||
/tasks - List background tasks
|
||||
/retry - Retry last message
|
||||
/help - Show this help"""
|
||||
|
||||
@@ -15,6 +15,7 @@ from bot.commands import handle_command
|
||||
from bot.feishu import send_text
|
||||
from config import FEISHU_APP_ID, FEISHU_APP_SECRET, is_user_allowed
|
||||
from orchestrator.agent import agent
|
||||
from orchestrator.tools import set_current_chat
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -87,6 +88,8 @@ def _handle_message(data: P2ImMessageReceiveV1) -> None:
|
||||
async def _process_message(user_id: str, chat_id: str, text: str) -> None:
|
||||
"""Process message: check allowlist, then commands, then agent."""
|
||||
try:
|
||||
set_current_chat(chat_id)
|
||||
|
||||
if not is_user_allowed(user_id):
|
||||
logger.warning("Rejected message from unauthorized user: ...%s", user_id[-8:])
|
||||
await send_text(chat_id, "chat_id", "Sorry, you are not authorized to use this bot.")
|
||||
|
||||
Reference in New Issue
Block a user