""" ExecutionAgent V2 - 集成StageToolRegistry 支持执行bbav20311分析阶段脚本 """ import asyncio from typing import Dict, List, Optional from .base import AgentMessage, AgentState, BaseAgent from gfa_core.mas.llm import LLMManager from gfa_core.project_paths import WORKSPACE_ROOT class ExecutionAgent(BaseAgent): """ 任务执行Agent V2 使用StageToolRegistry执行实际的分析阶段 """ name = "execution" role = "Task Execution Specialist" def __init__(self, llm_manager: LLMManager, stage_registry=None): super().__init__(llm_manager) self.stage_registry = stage_registry async def execute(self, state: AgentState, message: AgentMessage) -> AgentState: """ 执行分析任务 从state中提取任务信息,使用StageToolRegistry执行 """ print(f"[ExecutionAgent] 开始执行,session_id: {state.session_id}") # 获取任务信息 task_plan = state.results.get("task_plan", {}) stages_detail = task_plan.get("stages", []) # 优先使用用户传入的 job_id,其次使用 session_id job_id = state.results.get("job_id") or state.session_id or "default_job" prefix = state.results.get("prefix", "") print(f"[ExecutionAgent] task_plan: {task_plan}") print(f"[ExecutionAgent] stages_detail: {stages_detail}") print(f"[ExecutionAgent] job_id: {job_id}, prefix: {prefix}") # 提取 stage_id 列表(支持 dict 或 string) stages_to_run = [] for stage in stages_detail: if isinstance(stage, dict): stages_to_run.append(stage.get("id", "unknown")) else: stages_to_run.append(stage) print(f"[ExecutionAgent] stages_to_run: {stages_to_run}") # 获取意图信息(用于参数) intent = state.results.get("results", {}).get("intent", {}) or state.results.get("intent", {}) print(f"[ExecutionAgent] intent: {intent}") if not stages_to_run: # 检查是否是因为PreFlight验证失败导致没有可执行的阶段 # preflight_result在task_plan中,key是"preflight_result" preflight_result = task_plan.get("preflight_result", {}) task_plan_valid = task_plan.get("valid", True) task_plan_error = task_plan.get("error", "") if not task_plan_valid: # PreFlight验证失败,返回错误而不是加载旧结果 error_msg = task_plan_error or "执行前验证失败" print(f"[ExecutionAgent] ❌ PreFlight验证失败,无法执行: {error_msg}") state.messages.append({ "role": "execution", "content": f"❌ 执行前验证失败: {error_msg}" }) # AgentState使用results字典 state.results["execution_status"] = "error" state.results["execution_error"] = error_msg state.results["execution_results"] = [] return state # 如果没有需要执行的阶段(可能都已完成了),从manifest加载已有结果 print(f"[ExecutionAgent] ✅ 没有需要执行的阶段(可能都已完成了),从manifest加载结果") # 从manifest加载已完成阶段的结果 completed_results = [] job_id = state.results.get("job_id") or state.session_id prefix = state.results.get("prefix", "") try: from pathlib import Path import json workspace = WORKSPACE_ROOT / job_id / "final" if workspace.exists(): for manifest_file in workspace.glob(f"{prefix}.*.manifest.json"): try: with open(manifest_file, 'r') as f: manifest = json.load(f) stage = manifest.get("stage", "unknown") completed_results.append({ "stage": stage, "result": { "status": manifest.get("status", "success"), "manifest": manifest, "manifest_path": str(manifest_file), "message": f"✅ {stage.capitalize()} 完成(从manifest加载)" } }) print(f"[ExecutionAgent] 加载manifest: {manifest_file.name}, stage: {stage}") except Exception as e: print(f"[ExecutionAgent] 加载manifest失败: {e}") except Exception as e: print(f"[ExecutionAgent] 扫描manifest目录失败: {e}") state.messages.append({ "role": "execution", "content": f"✅ 所有阶段已完成,加载 {len(completed_results)} 个已有结果" }) state.results["execution_status"] = "success" state.results["execution_results"] = completed_results state.results["execution_error"] = None return state # 检查stage_registry是否可用 print(f"[ExecutionAgent] stage_registry: {self.stage_registry}") if self.stage_registry is None: print("[ExecutionAgent] ❌ Stage registry not available") state.messages.append({ "role": "execution", "content": "⚠️ Stage registry not available, cannot execute analysis" }) state.results["execution_status"] = "error" state.results["execution_error"] = "Stage registry not initialized" return state print(f"[ExecutionAgent] ✅ Stage registry available, stages: {self.stage_registry.list_all()}") # 执行每个阶段 execution_results = [] overall_status = "success" print(f"[ExecutionAgent] 开始执行 {len(stages_to_run)} 个阶段") for stage_id in stages_to_run: print(f"[ExecutionAgent] 处理阶段: {stage_id}") # 检查阶段是否存在 try: stage_tool = self.stage_registry.get(stage_id) print(f"[ExecutionAgent] stage_tool: {stage_tool}") except Exception as e: print(f"[ExecutionAgent] ❌ 获取 stage_tool 失败: {e}") import traceback traceback.print_exc() state.messages.append({ "role": "execution", "content": f"❌ Stage '{stage_id}' 获取失败: {str(e)}" }) overall_status = "error" continue if stage_tool is None: print(f"[ExecutionAgent] ❌ Stage '{stage_id}' not found") state.messages.append({ "role": "execution", "content": f"❌ Stage '{stage_id}' not found in registry" }) overall_status = "error" continue # 通知开始执行 print(f"[ExecutionAgent] 🚀 开始执行 {stage_tool.name} ({stage_id})") state.messages.append({ "role": "execution", "content": f"🚀 Starting {stage_tool.name} ({stage_id})..." }) # 准备参数 extra_params = state.results.get("params", {}).copy() extra_params.update(intent.get("params", {})) print(f"[ExecutionAgent] extra_params: {extra_params}") # 执行阶段 try: print(f"[ExecutionAgent] 调用 stage_registry.execute({stage_id}, {job_id}, {prefix})") # stage_registry.execute 现在已经是 async,直接 await result = await self.stage_registry.execute( stage_id=stage_id, job_id=job_id, prefix=prefix, extra_params=extra_params ) print(f"[ExecutionAgent] ✅ 执行完成,结果: {result}") execution_results.append({ "stage": stage_id, "result": result }) if result.get("status") in ["success", "partial_success"]: state.messages.append({ "role": "execution", "content": f"✅ {stage_tool.name} completed successfully" }) else: # 提取错误信息(优先使用error字段,否则使用message字段) error_msg = result.get('error') or result.get('message', 'Unknown error') # 从日志文件读取详细错误信息 stderr = result.get('stderr', '') stdout = result.get('stdout', '') # 如果stderr为空,尝试从日志文件读取 if not stderr and result.get('manifest_path'): try: from pathlib import Path manifest_path = Path(result['manifest_path']) logs_dir = manifest_path.parent.parent / "logs" if logs_dir.exists(): import glob log_files = glob.glob(str(logs_dir / f"*_{stage_id}.log")) if log_files: latest_log = max(log_files, key=lambda x: Path(x).stat().st_mtime) with open(latest_log, 'r', encoding='utf-8', errors='ignore') as f: log_content = f.read() stderr = log_content[-2000:] # 最后2000字符 except Exception as e: print(f"[ExecutionAgent] 读取日志文件失败: {e}") state.messages.append({ "role": "execution", "content": f"❌ {stage_tool.name} failed: {error_msg}" }) overall_status = "error" # 更新最后一个execution_result,添加错误详情 if execution_results: execution_results[-1]["error_details"] = { "error": error_msg, "stderr": stderr, "stdout": stdout, "message": result.get('message', '') } break except Exception as e: execution_results.append({ "stage": stage_id, "result": {"status": "error", "error": str(e)} }) state.messages.append({ "role": "execution", "content": f"❌ Exception in {stage_tool.name}: {str(e)}" }) overall_status = "error" break # 更新状态 - 保存到AgentState.results(供其他Agent使用) state.results["execution_results"] = execution_results state.results["execution_status"] = overall_status if overall_status == "error": for item in execution_results: result = item.get("result", {}) if isinstance(item, dict) else {} error_msg = result.get("error") or result.get("message") if error_msg: state.results["execution_error"] = error_msg break return state async def execute_single_stage(self, state: AgentState, stage_id: str) -> dict: """ 执行单个分析阶段 Args: state: 当前Agent状态 stage_id: 阶段ID Returns: 执行结果字典 """ if self.stage_registry is None: return {"status": "error", "error": "Stage registry not initialized"} job_id = state.session_id or state.results.get("job_id", "default_job") prefix = state.results.get("prefix", "") params = state.results.get("params", {}) # stage_registry.execute 现在已经是 async,直接 await return await self.stage_registry.execute( stage_id=stage_id, job_id=job_id, prefix=prefix, extra_params=params ) def get_available_stages(self) -> List[str]: """获取可用的分析阶段列表""" if self.stage_registry is None: return [] return [s.id for s in self.stage_registry.list_all()]