first commit

This commit is contained in:
2025-12-21 13:42:30 +01:00
parent 823b825acb
commit f9b24fe248
47 changed files with 8222 additions and 1 deletions

174
tools/ai-review/review.py Normal file
View File

@@ -0,0 +1,174 @@
import json
import os
import subprocess
import sys
import requests
import yaml
from comment import to_markdown
ROOT = os.path.dirname(__file__)
CFG = yaml.safe_load(open(f"{ROOT}/config.yml"))
# Marker to identify the AI comment
AI_MARKER = "<!-- AI_CODE_REVIEW -->"
# Disclaimer text to prepend
AI_DISCLAIMER = (
"**Note:** This review was generated by an AI assistant. "
"While it aims to be accurate and helpful, it may contain mistakes "
"or miss important issues. Please verify all findings before taking action."
)
# -------------------------------
# Helper functions
# -------------------------------
def get_diff() -> str:
"""Get git diff against main branch, limited by config"""
diff = subprocess.check_output(["git", "diff", "origin/main...HEAD"], text=True)
lines = diff.splitlines()
if len(lines) > CFG["review"]["max_diff_lines"]:
return "\n".join(lines[: CFG["review"]["max_diff_lines"]])
return diff
def build_prompt(diff: str) -> str:
"""Prepare the AI prompt with the diff"""
base = open(f"{ROOT}/prompts/base.md").read()
return f"{base}\n\nDIFF:\n{diff}"
def call_llm(prompt: str) -> str:
"""Call the configured LLM provider"""
provider = CFG["provider"]
if provider == "openai":
r = requests.post(
"https://api.openai.com/v1/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": CFG["model"]["openai"],
"temperature": CFG["temperature"],
"messages": [{"role": "user", "content": prompt}],
},
timeout=60,
)
return r.json()["choices"][0]["message"]["content"]
if provider == "openrouter":
r = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={
"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": CFG["model"]["openrouter"],
"messages": [{"role": "user", "content": prompt}],
},
timeout=60,
)
return r.json()["choices"][0]["message"]["content"]
if provider == "ollama":
r = requests.post(
f"{os.environ['OLLAMA_HOST']}/api/generate",
json={
"model": CFG["model"]["ollama"],
"prompt": prompt,
"stream": False,
},
timeout=120,
)
return r.json()["response"]
raise RuntimeError("Unknown provider")
# -------------------------------
# Gitea PR comment functions
# -------------------------------
def find_existing_comment() -> int | None:
"""Find existing AI review comment in the PR"""
url = (
f"{os.environ['AI_REVIEW_API_URL']}/repos/"
f"{os.environ['AI_REVIEW_REPO']}/issues/"
f"{os.environ['AI_REVIEW_PR_NUMBER']}/comments"
)
r = requests.get(
url,
headers={"Authorization": f"token {os.environ['AI_REVIEW_TOKEN']}"},
timeout=15,
)
for c in r.json():
if AI_MARKER in c["body"]:
return c["id"]
return None
def upsert_pr_comment(markdown: str):
"""Create or update the PR comment"""
comment_id = find_existing_comment()
headers = {
"Authorization": f"token {os.environ['AI_REVIEW_TOKEN']}",
"Content-Type": "application/json",
}
if comment_id:
url = (
f"{os.environ['AI_REVIEW_API_URL']}/repos/"
f"{os.environ['AI_REVIEW_REPO']}/issues/comments/{comment_id}"
)
r = requests.patch(url, headers=headers, json={"body": markdown})
else:
url = (
f"{os.environ['AI_REVIEW_API_URL']}/repos/"
f"{os.environ['AI_REVIEW_REPO']}/issues/"
f"{os.environ['AI_REVIEW_PR_NUMBER']}/comments"
)
r = requests.post(url, headers=headers, json={"body": markdown})
if r.status_code not in (200, 201):
raise RuntimeError(f"Failed to upsert PR comment: {r.text}")
# -------------------------------
# Main workflow
# -------------------------------
def main():
diff = get_diff()
if not diff.strip():
sys.exit(0)
raw = call_llm(build_prompt(diff))
result = json.loads(raw)
# Convert JSON review to Markdown
markdown = to_markdown(result)
# Prepend AI disclaimer and marker
full_comment = AI_DISCLAIMER + "\n\n" + AI_MARKER + "\n" + markdown
upsert_pr_comment(full_comment)
# Fail CI if severity is HIGH
if result["overall_severity"] == CFG["review"][
"fail_on_severity"
] and not result.get("approval", False):
sys.exit(1)
if __name__ == "__main__":
main()