"""GeminiCaller — gemini -p 역할별 headless 호출. cmd /c 래핑으로 PowerShell 실행 정책 우회. """ import asyncio import json import time from pathlib import Path ROLE_PROMPTS_DIR = Path(__file__).parent.parent / "prompts" class GeminiCaller: """Gemini CLI headless 호출을 관리합니다.""" def __init__(self, project_path: str = None): self.project_path = project_path self.call_count = 0 self.last_call_time = 0.0 async def call(self, role: str, context: str, timeout: int = 120) -> str: """역할별 프롬프트로 gemini -p 호출. Args: role: 프롬프트 파일명 (planner, coder, reviewer, tester) context: 전달할 컨텍스트 timeout: 최대 대기 시간 (초) """ # 시스템 프롬프트 로드 prompt_file = ROLE_PROMPTS_DIR / f"{role}.md" if prompt_file.exists(): system_prompt = prompt_file.read_text(encoding="utf-8") else: system_prompt = f"You are a {role}. Respond in Korean." # cmd 구성 cmd_parts = ["gemini", "-p", context] if system_prompt: cmd_parts.extend(["--system", system_prompt]) cmd_parts.extend(["--approval-mode", "yolo"]) if self.project_path: cmd_parts.extend(["--include-directories", self.project_path]) # cmd /c 래핑 (PowerShell 실행 정책 우회) escaped_context = context.replace('"', '\\"') cmd_str = f'gemini -p "{escaped_context}" --approval-mode yolo' if self.project_path: cmd_str += f' --include-directories "{self.project_path}"' try: proc = await asyncio.create_subprocess_shell( f'cmd /c {cmd_str}', stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, stderr = await asyncio.wait_for( proc.communicate(), timeout=timeout ) self.call_count += 1 self.last_call_time = time.time() output = stdout.decode("utf-8", errors="replace").strip() # YOLO 모드 메시지 제거 lines = output.splitlines() cleaned = [] for line in lines: if "YOLO mode" in line or "Loaded cached" in line: continue cleaned.append(line) return "\n".join(cleaned).strip() except asyncio.TimeoutError: return f"[ERROR] Gemini CLI timeout after {timeout}s" except Exception as e: return f"[ERROR] Gemini CLI call failed: {e}" async def call_simple(self, prompt: str, timeout: int = 60) -> str: """시스템 프롬프트 없이 단순 호출.""" return await self.call("default", prompt, timeout)