diff --git a/src/daemon/spawner.py b/src/daemon/spawner.py index c8e6e39..69d6b58 100644 --- a/src/daemon/spawner.py +++ b/src/daemon/spawner.py @@ -19,6 +19,64 @@ from src.blackboard.db import get_connection, init_db logger = logging.getLogger("moziplus-v2.spawner") +# ── Prompt 模板 ── + +SPAWN_PROMPT_TEMPLATE = """你收到一个 v2.6 黑板任务,请按步骤执行。 + +## 任务信息 + +- 项目: {project_id} +- 任务ID: {task_id} +- 标题: {title} +- 描述: {description} +- 类型: {task_type} +- 优先级: {priority} +- 必要条件: {must_haves} + +## 执行步骤 + +1. 了解任务需求,确认理解无误 +2. 执行任务(编码/回测/数据检查/审查等) + +## ⚠️ 完成后必须回写(关键!) + +你必须完成以下 API 调用才算任务完成。如果你只执行了步骤 1-2 但没有调 API 回写,任务将永远不会完成。 + +### 步骤 3: 写入产出 +``` +POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_id}/outputs +Content-Type: application/json + +{{"agent": "{agent_id}", "content": "<你的产出内容>", "content_type": "report"}} +``` + +content_type 可选: "report"(文本报告), "code"(代码), "data"(数据路径), "file"(文件路径) + +### 步骤 4: 更新任务状态 +如果任务成功完成: +``` +POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_id}/status +Content-Type: application/json + +{{"status": "review", "agent": "{agent_id}"}} +``` + +如果遇到问题无法完成: +``` +POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_id}/status +Content-Type: application/json + +{{"status": "failed", "agent": "{agent_id}", "detail": "<失败原因>"}} +``` + +## 注意 +- API 地址: http://{api_host}:{api_port} +- 查看完整任务信息: GET /api/projects/{project_id}/tasks/{task_id}?expand=all +- 写入评论: POST /api/projects/{project_id}/tasks/{task_id}/comments +- 产出写入后,审查流水线会自动触发 +""" + + class AgentSpawner: """Agent spawn 管理""" @@ -27,16 +85,22 @@ class AgentSpawner: db_path: Optional[Path] = None, agent_timeout: float = 600.0, dry_run: bool = False, + api_host: str = "127.0.0.1", + api_port: int = 8083, ): """ Args: db_path: 项目黑板 DB 路径(用于写 task_attempts) agent_timeout: Agent 超时秒数 dry_run: 测试模式,不实际 spawn + api_host: API 地址(供 Agent 回写) + api_port: API 端口(供 Agent 回写) """ self.db_path = db_path self.agent_timeout = agent_timeout self.dry_run = dry_run + self.api_host = api_host + self.api_port = api_port # session 注册表 {session_id: {...}} self._sessions: Dict[str, Dict[str, Any]] = {} @@ -47,6 +111,31 @@ class AgentSpawner: return {sid: s for sid, s in self._sessions.items() if s.get("status") == "running"} + def build_spawn_message( + self, + task_id: str, + title: str, + description: str, + task_type: str = "", + priority: int = 5, + must_haves: str = "", + project_id: str = "", + agent_id: str = "", + ) -> str: + """构建 Agent spawn 的消息(使用 prompt 模板)""" + return SPAWN_PROMPT_TEMPLATE.format( + project_id=project_id, + task_id=task_id, + title=title, + description=description or "(无描述)", + task_type=task_type or "general", + priority=priority, + must_haves=must_haves or "(无)", + agent_id=agent_id, + api_host=self.api_host, + api_port=self.api_port, + ) + async def spawn_full_agent( self, agent_id: str,