From 8140f75c7f2b24ba31ffd8e21c52af8dd42cd30a Mon Sep 17 00:00:00 2001 From: CD Date: Fri, 6 Mar 2026 22:25:26 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=A6=AC=EB=B7=B0=EC=96=B4=EA=B0=80=20?= =?UTF-8?q?=EC=8B=A4=EC=A0=9C=20=ED=8C=8C=EC=9D=BC=20=EC=9D=BD=EA=B8=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - batch_review: Gemini stdout 대신 프로젝트의 최근 변경 파일(60초)을 읽어 리뷰 - 파일 삭제/변경 없는 작업은 자동 통과 - 에이전트 보고 + 실제 파일 내용을 함께 전달 - 최대 10개 파일, 파일당 3000자 제한 --- core/task_pipeline.py | 62 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/core/task_pipeline.py b/core/task_pipeline.py index 0880953..2883382 100644 --- a/core/task_pipeline.py +++ b/core/task_pipeline.py @@ -118,23 +118,63 @@ class TaskPipeline: # ────────────────────────────────────────── async def batch_review(self, tasks: list[dict], code_outputs: list[str]) -> dict: - """모든 코드 출력을 한 번에 리뷰.""" - combined = [] - for i, (task, output) in enumerate(zip(tasks, code_outputs)): + """에이전트가 생성/수정한 실제 파일을 리뷰. + + code_outputs(에이전트 보고)와 함께 실제 프로젝트 파일 내용을 읽어서 리뷰합니다. + """ + import os + import time as _time + + # 태스크 요약 + task_summaries = [] + for i, task in enumerate(tasks): title = task.get("title", task.get("description", f"Task {i+1}")) - combined.append( - f"### Task {i+1}: {title}\n" - f"{output[:2000]}\n" - ) + task_summaries.append(f"### Task {i+1}: {title}") + + # 에이전트 보고 요약 + agent_reports = [] + for i, output in enumerate(code_outputs): + agent_reports.append(f"--- Agent {i+1} 보고 ---\n{output[:1000]}") + + # 최근 변경된 파일 읽기 (60초 이내) + recent_files = [] + cutoff = _time.time() - 60 + project_root = Path(self.project_path) + skip_dirs = {".git", "__pycache__", "node_modules", ".venv", "venv"} + + for root, dirs, files in os.walk(self.project_path): + dirs[:] = [d for d in dirs if d not in skip_dirs] + for fname in files: + fpath = Path(root) / fname + try: + if fpath.stat().st_mtime > cutoff: + rel = fpath.relative_to(project_root) + content = fpath.read_text(encoding="utf-8", errors="replace") + recent_files.append( + f"### {rel}\n```\n{content[:3000]}\n```" + ) + except (OSError, UnicodeDecodeError): + continue + + if not recent_files: + # 변경 파일 없음 → 자동 통과 (삭제 작업 등) + return { + "passed": True, + "summary": "파일 변경 없음 또는 삭제 작업 — 자동 통과", + "issues": [], + } + + files_section = "\n\n".join(recent_files[:10]) # 최대 10개 prompt = ( - f"## All Code Changes\n\n" - f"{'---'.join(combined)}\n\n" - f"Review ALL changes above as a whole." + f"## 요청된 태스크\n{chr(10).join(task_summaries)}\n\n" + f"## 에이전트 보고\n{chr(10).join(agent_reports)}\n\n" + f"## 실제 생성/수정된 파일\n{files_section}\n\n" + f"위 파일들이 태스크 요구사항을 충족하는지 리뷰하세요." ) response = await self.gemini.call("reviewer", prompt, timeout=180) - self._log("batch_review", f"{len(tasks)} tasks", response) + self._log("batch_review", f"{len(tasks)} tasks, {len(recent_files)} files", response) review = self._extract_json(response) return review or {"passed": True, "summary": response, "raw": response}