Files
JARVIS/backend/app/agents/tools/direct_executor.py
WIN-JHFT4D3SIVT\caoxiaozhu 5667190abe feat(agents): implement Code Commander module (Phases 1-5)
- Phase 1: Infrastructure (state, prompts, registry)
- Phase 2: Execution engine (AI adapters, security classifier, executors)
- Phase 3: Agent integration (graph nodes, routing)
- Phase 4: Streaming interaction (PTY terminal, WebSocket)
- Phase 5: Frontend integration (Vue components)
2026-04-05 14:56:45 +08:00

113 lines
3.1 KiB
Python

"""
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="",
)