feat: 출력 파싱 4패턴 지원 + 실패 기록 + Gemini CLI Windows 호환
- file_applier.py: === FILE ===, `lang:path, // file: comment, **header**+code 4패턴 경로 검증, 중복 제거, 빈 내용 스킵, 소스 추적 - task_pipeline.py: try/except/finally로 성공/실패 모두 docs 기록 파싱 실패 추적, 에러를 총평 warnings에 전파 - gemini_caller.py: Windows에서 cmd /c gemini 사용 (PS ExecutionPolicy 우회) - Gemini CLI stdin 파이프 동작 검증 완료
This commit is contained in:
@@ -172,7 +172,10 @@ class TaskPipeline:
|
||||
# ──────────────────────────────────────────
|
||||
|
||||
async def execute(self, user_request: str) -> dict:
|
||||
"""Plan → Code(병렬) → 파일 적용 → Review → 총평 → 기록."""
|
||||
"""Plan -> Code(병렬) -> 파일 적용 -> Review -> 총평 -> 기록.
|
||||
|
||||
성공/실패 모두 docs에 기록됩니다.
|
||||
"""
|
||||
result = {
|
||||
"request": user_request,
|
||||
"plan": None,
|
||||
@@ -180,53 +183,96 @@ class TaskPipeline:
|
||||
"review": None,
|
||||
"applied_files": [],
|
||||
"summary": None,
|
||||
"errors": [],
|
||||
}
|
||||
|
||||
# 1. Plan
|
||||
plan = await self.plan(user_request)
|
||||
result["plan"] = plan
|
||||
try:
|
||||
# 1. Plan
|
||||
plan = await self.plan(user_request)
|
||||
result["plan"] = plan
|
||||
|
||||
tasks = plan.get("tasks", [])
|
||||
if not tasks:
|
||||
tasks = plan.get("tasks", [])
|
||||
if not tasks:
|
||||
result["summary"] = {
|
||||
"title": "태스크 없음",
|
||||
"summary": "Planner가 태스크를 생성하지 못했습니다.",
|
||||
"changes": [],
|
||||
"warnings": ["요청을 더 구체적으로 해주세요."],
|
||||
"next_steps": [],
|
||||
}
|
||||
self.docs.record_session(user_request, result["summary"], plan)
|
||||
return result
|
||||
|
||||
# 2. Code 병렬 실행
|
||||
code_outputs = await self.code_parallel(tasks)
|
||||
result["code_outputs"] = [o[:500] for o in code_outputs]
|
||||
|
||||
# 에러 추적
|
||||
error_count = sum(1 for o in code_outputs if o.startswith("[ERROR]"))
|
||||
if error_count > 0:
|
||||
result["errors"].append(f"코딩 실패: {error_count}/{len(tasks)}개 태스크")
|
||||
|
||||
# 3. 파일 적용
|
||||
all_applied = []
|
||||
parse_failures = 0
|
||||
for i, output in enumerate(code_outputs):
|
||||
if output.startswith("[ERROR]"):
|
||||
continue
|
||||
changes = parse_code_output(output)
|
||||
if changes:
|
||||
applied = apply_changes(changes, self.project_path)
|
||||
all_applied.extend(applied)
|
||||
else:
|
||||
parse_failures += 1
|
||||
result["errors"].append(
|
||||
f"Task {i+1} 출력에서 파일을 추출하지 못함 "
|
||||
f"(출력 {len(output)}자)"
|
||||
)
|
||||
result["applied_files"] = all_applied
|
||||
|
||||
if parse_failures > 0:
|
||||
self._log(
|
||||
"parse_warning",
|
||||
f"{parse_failures}/{len(tasks)} 파싱 실패",
|
||||
f"적용 성공: {len(all_applied)}개 파일",
|
||||
)
|
||||
|
||||
# 4. Batch Review
|
||||
review = await self.batch_review(tasks, code_outputs)
|
||||
result["review"] = review
|
||||
|
||||
# 5. 총평
|
||||
summary = await self.summarize(
|
||||
user_request, plan, code_outputs, review, all_applied
|
||||
)
|
||||
# 에러 정보를 총평에 추가
|
||||
if result["errors"]:
|
||||
existing_warnings = summary.get("warnings", [])
|
||||
summary["warnings"] = existing_warnings + result["errors"]
|
||||
result["summary"] = summary
|
||||
|
||||
except Exception as e:
|
||||
# 파이프라인 자체 실패
|
||||
result["errors"].append(f"파이프라인 오류: {str(e)}")
|
||||
result["summary"] = {
|
||||
"title": "태스크 없음",
|
||||
"summary": "Planner가 태스크를 생성하지 못했습니다.",
|
||||
"title": "작업 실패",
|
||||
"summary": f"파이프라인 실행 중 오류 발생: {str(e)}",
|
||||
"changes": [],
|
||||
"warnings": ["요청을 더 구체적으로 해주세요."],
|
||||
"next_steps": [],
|
||||
"warnings": result["errors"],
|
||||
"next_steps": ["오류 내용 확인 후 다시 시도"],
|
||||
}
|
||||
return result
|
||||
self._log("pipeline_error", user_request, str(e))
|
||||
|
||||
# 2. Code 병렬 실행
|
||||
code_outputs = await self.code_parallel(tasks)
|
||||
result["code_outputs"] = [o[:500] for o in code_outputs]
|
||||
|
||||
# 3. 파일 적용
|
||||
all_applied = []
|
||||
for output in code_outputs:
|
||||
if output.startswith("[ERROR]"):
|
||||
continue
|
||||
changes = parse_code_output(output)
|
||||
if changes:
|
||||
applied = apply_changes(changes, self.project_path)
|
||||
all_applied.extend(applied)
|
||||
result["applied_files"] = all_applied
|
||||
|
||||
# 4. Batch Review
|
||||
review = await self.batch_review(tasks, code_outputs)
|
||||
result["review"] = review
|
||||
|
||||
# 5. 총평
|
||||
summary = await self.summarize(
|
||||
user_request, plan, code_outputs, review, all_applied
|
||||
)
|
||||
result["summary"] = summary
|
||||
|
||||
# 6. 기록
|
||||
self.docs.record_session(user_request, summary, plan)
|
||||
self.docs.append_changelog(
|
||||
summary.get("title", user_request[:50])
|
||||
)
|
||||
finally:
|
||||
# 성공/실패 모두 기록
|
||||
self.docs.record_session(
|
||||
user_request,
|
||||
result.get("summary", {"summary": "기록 없음"}),
|
||||
result.get("plan"),
|
||||
)
|
||||
self.docs.append_changelog(
|
||||
result.get("summary", {}).get("title", user_request[:50])
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user