feat: add Main Agent core service, tools, and Celery tasks (Phase 2)

数字员工大脑 — Main Agent 核心实现:
- MainAgentService: 目标分解(LLM)、任务调度、进度监控、失败重试、自主循环
- 4个 Main Agent 专有工具: create_task / assign_task / check_progress / notify_user
- Celery 异步任务: decompose_goal / execute_goal / execute_task / autonomy_tick
- Goal API 增强: decompose / execute-async / replan 端点

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
renjianbo
2026-05-08 19:58:53 +08:00
parent 02d7cf8f62
commit 926ec6c0a1
5 changed files with 980 additions and 2 deletions

View File

@@ -0,0 +1,132 @@
"""
Goal/Task 异步任务 — Celery 任务定义
Main Agent 的目标分解、任务执行、自主循环等重量级操作通过 Celery 异步执行。
"""
from app.core.tools_bootstrap import ensure_builtin_tools_registered
ensure_builtin_tools_registered()
from app.core.celery_app import celery_app
from app.core.database import SessionLocal
from app.models.goal import Goal
from app.models.execution import Execution
from app.services.main_agent_service import MainAgentService
import asyncio
import logging
import time
logger = logging.getLogger(__name__)
@celery_app.task(bind=True)
def decompose_goal_task(self, goal_id: str):
"""
异步分解目标:使用 LLM 将 Goal 分解为 Task 树。
在 Celery Worker 中执行,避免 API 请求超时。
"""
db = SessionLocal()
try:
service = MainAgentService(db)
goal = asyncio.run(service.decompose_goal(goal_id))
return {
"status": "completed",
"goal_id": goal_id,
"goal_title": goal.title,
}
except Exception as e:
logger.error(f"Goal decomposition failed: {e}", exc_info=True)
db.rollback()
return {"status": "failed", "goal_id": goal_id, "error": str(e)}
finally:
db.close()
@celery_app.task(bind=True)
def execute_goal_task(self, goal_id: str):
"""
异步执行 Goal:启动 Main Agent 管理目标全生命周期。
1. 分解目标(如果尚未分解)
2. 持续执行 task 直到完成或阻塞
3. 更新 Goal 状态
"""
db = SessionLocal()
start_time = time.time()
try:
goal = db.query(Goal).filter(Goal.id == goal_id).first()
if not goal:
return {"status": "failed", "goal_id": goal_id, "error": "目标不存在"}
# 更新状态
goal.status = "active"
db.commit()
service = MainAgentService(db)
result = asyncio.run(service.start_goal_execution(goal_id))
elapsed = int((time.time() - start_time) * 1000)
return {
"status": "completed",
"goal_id": goal_id,
"elapsed_ms": elapsed,
**result,
}
except Exception as e:
logger.error(f"Goal execution failed: {e}", exc_info=True)
goal = db.query(Goal).filter(Goal.id == goal_id).first()
if goal:
goal.status = "failed"
db.commit()
return {"status": "failed", "goal_id": goal_id, "error": str(e)}
finally:
db.close()
@celery_app.task(bind=True)
def execute_task_celery(self, task_id: str):
"""
异步执行单个 Task。
Main Agent 创建 Execution 记录后将任务交给 Celery Worker 执行。
"""
db = SessionLocal()
start_time = time.time()
try:
service = MainAgentService(db)
result = asyncio.run(service.execute_task(task_id))
elapsed = int((time.time() - start_time) * 1000)
return {
"status": result.get("status", "completed"),
"task_id": task_id,
"elapsed_ms": elapsed,
**result,
}
except Exception as e:
logger.error(f"Task execution failed: {e}", exc_info=True)
return {"status": "failed", "task_id": task_id, "error": str(e)}
finally:
db.close()
@celery_app.task(bind=True)
def autonomy_tick_task(self, goal_id: str):
"""
自主循环单次心跳:检查进度 → 执行可运行任务 → 处理失败 → 通知。
由 Celery Beat 定时调度(根据 Goal.autonomy_config.check_interval_minutes)。
"""
db = SessionLocal()
try:
service = MainAgentService(db)
result = asyncio.run(service.autonomy_tick(goal_id))
logger.info(f"Autonomy tick for goal {goal_id}: {result.get('status', 'unknown')}")
return {"status": "completed", "goal_id": goal_id, **result}
except Exception as e:
logger.error(f"Autonomy tick failed for goal {goal_id}: {e}", exc_info=True)
return {"status": "failed", "goal_id": goal_id, "error": str(e)}
finally:
db.close()