""" Direct Executor - 直接执行器 用于低风险任务,直接执行不隔离 """ import asyncio import os import shutil import tempfile from pathlib import Path from typing import AsyncGenerator from app.agents.tools.ai_adapter import AICLIAdapter class ExecutionResult: """执行结果""" def __init__( self, success: bool, exit_code: int, stdout: str, stderr: str, ): self.success = success self.exit_code = exit_code self.stdout = stdout self.stderr = stderr class DirectExecutor: """直接执行器(用于低风险任务)""" def __init__(self, adapter: AICLIAdapter, timeout: int = 60): self.adapter = adapter self.timeout = timeout async def execute( self, prompt: str, ) -> AsyncGenerator[str, None]: """ 直接执行,不需要沙盒 Args: prompt: 任务描述 Yields: str: 实时输出 """ # 1. 检查 CLI 是否安装 if not self.adapter.is_installed(): yield f"[ERROR] {self.adapter.cli_name} is not installed\n" yield f"[ERROR] Please install {self.adapter.cli_name} first\n" return # 2. 构建命令 cmd = self.adapter.build_command(prompt, None) # 3. 异步执行,实时 yield 输出 process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, env={**os.environ, "TERM": "xterm-256color"}, ) # 4. 实时读取输出 stdout_lines = [] stderr_lines = [] while True: try: line_bytes = await asyncio.wait_for( process.stdout.readline(), timeout=self.timeout, ) if not line_bytes: break line = line_bytes.decode("utf-8", errors="replace") stdout_lines.append(line) yield line except asyncio.TimeoutError: process.kill() yield f"\n[ERROR] Execution timed out after {self.timeout}s\n" break # 5. 读取 stderr stderr_bytes = await process.communicate() if stderr_bytes[1]: stderr = stderr_bytes[1].decode("utf-8", errors="replace") stderr_lines.append(stderr) yield f"\n[STDERR]\n{stderr}\n" # 6. 完成标记 yield f"\n[EXIT_CODE] {process.returncode or 0}\n" yield f"\n[COMPLETE] success={process.returncode == 0}\n" async def execute_sync(self, prompt: str) -> ExecutionResult: """同步执行并返回完整结果""" output_parts = [] async for line in self.execute(prompt): output_parts.append(line) output = "".join(output_parts) return ExecutionResult( success="[COMPLETE] success=True" in output, exit_code=0, stdout=output, stderr="", )