126 lines
3.5 KiB
Python
126 lines
3.5 KiB
Python
from __future__ import annotations
|
||
|
||
import re
|
||
from dataclasses import dataclass
|
||
|
||
from .models import IssueRecord, RepositoryRecord
|
||
|
||
|
||
VALID_VERDICTS = {"APPROVE", "REQUEST_CHANGES", "NEEDS_HUMAN_DECISION"}
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class ReviewReport:
|
||
verdict: str
|
||
raw: str
|
||
suggested_pr_comment: str
|
||
|
||
|
||
def render_implementer_prompt(repo: RepositoryRecord, issue: IssueRecord, branch_name: str) -> str:
|
||
return f"""# Agent Implementation Task
|
||
|
||
Repository: {repo.full_name}
|
||
Base branch: {repo.default_branch}
|
||
Working branch: {branch_name}
|
||
Issue: #{issue.issue_number} {issue.title}
|
||
Issue URL: {issue.html_url}
|
||
|
||
## Issue Body
|
||
|
||
{issue.body or "(no issue body)"}
|
||
|
||
## Instructions
|
||
|
||
Implement the requested change in this workspace. Keep the change scoped to this issue.
|
||
Run the relevant tests before finishing.
|
||
|
||
Write `.agent-output/AGENT_IMPLEMENTATION_REPORT.md` using this exact section contract.
|
||
Keep the section headings exactly as written below, but write the section content in Chinese:
|
||
|
||
- Summary
|
||
- Files changed
|
||
- Test commands run
|
||
- Test results
|
||
- Known risks
|
||
- Follow-up suggestions
|
||
"""
|
||
|
||
|
||
def render_reviewer_prompt(repo: RepositoryRecord, issue: IssueRecord, pr_number: int) -> str:
|
||
return f"""# Agent Review Task
|
||
|
||
Repository: {repo.full_name}
|
||
Pull request: #{pr_number}
|
||
Issue: #{issue.issue_number} {issue.title}
|
||
|
||
Review the implementation currently checked out in this workspace. Focus on correctness,
|
||
scope control, test evidence, and human risks. Do not modify code.
|
||
|
||
Write `.agent-output/AGENT_REVIEW_REPORT.md` using this exact section contract.
|
||
Keep the section headings exactly as written below. Keep the Verdict token in English,
|
||
but write the section content and Suggested PR Comment in Chinese:
|
||
|
||
- Verdict: APPROVE, REQUEST_CHANGES, or NEEDS_HUMAN_DECISION
|
||
- Summary
|
||
- Correctness
|
||
- Scope Control
|
||
- Test Evidence
|
||
- Risks
|
||
- Required Human Checks
|
||
- Suggested PR Comment
|
||
"""
|
||
|
||
|
||
def render_pr_body(issue: IssueRecord, implementation_report: str) -> str:
|
||
return f"""关联 Issue:#{issue.issue_number}
|
||
|
||
## 代理实现报告
|
||
|
||
{implementation_report.strip()}
|
||
|
||
## 人工审核
|
||
|
||
此 PR 由本地 agent-manager 自动创建,但不会自动合并。
|
||
请维护者人工审核、决策并手动合并。
|
||
"""
|
||
|
||
|
||
def parse_review_report(raw: str) -> ReviewReport:
|
||
verdict_match = re.search(r"(?im)^\s*(?:[-*]\s*)?(?:##\s*)?Verdict\s*:?\s*`?([A-Z_]+)`?", raw)
|
||
verdict = verdict_match.group(1) if verdict_match else "NEEDS_HUMAN_DECISION"
|
||
if verdict not in VALID_VERDICTS:
|
||
verdict = "NEEDS_HUMAN_DECISION"
|
||
suggested = extract_section(raw, "Suggested PR Comment").strip()
|
||
if not suggested:
|
||
suggested = extract_inline_field(raw, "Suggested PR Comment").strip()
|
||
if not suggested:
|
||
suggested = raw.strip()
|
||
return ReviewReport(verdict=verdict, raw=raw, suggested_pr_comment=suggested)
|
||
|
||
|
||
def extract_section(raw: str, title: str) -> str:
|
||
pattern = re.compile(
|
||
rf"(?ims)^\s*##\s+{re.escape(title)}\s*$\n(?P<body>.*?)(?=^\s*##\s+|\Z)"
|
||
)
|
||
match = pattern.search(raw)
|
||
return match.group("body") if match else ""
|
||
|
||
|
||
def extract_inline_field(raw: str, title: str) -> str:
|
||
pattern = re.compile(rf"(?im)^\s*(?:[-*]\s*)?{re.escape(title)}\s*:\s*(?P<body>.+?)\s*$")
|
||
match = pattern.search(raw)
|
||
return match.group("body") if match else ""
|
||
|
||
|
||
def render_human_review_summary(review: ReviewReport) -> str:
|
||
return f"""## 代理评审摘要
|
||
|
||
结论:`{review.verdict}`
|
||
|
||
{review.suggested_pr_comment.strip()}
|
||
|
||
## 需要人工处理
|
||
|
||
请人工审核该 PR。agent-manager 不会自动合并、关闭 PR 或提交变更请求。
|
||
"""
|