Files
pr-agent-server/run_server.py
T

96 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""PR-Agent GitHub App + manifest callback server"""
import os, sys, json
# Configurable paths (systemd Nix deployment keeps secrets outside the store)
APP_DIR = os.environ.get("PR_AGENT_APP_DIR", "/var/lib/pr-agent-server")
private_key_path = os.environ.get(
"PRIVATE_KEY_PATH", os.path.join(APP_DIR, "private-key.pem")
)
omni_key_path = os.environ.get(
"OMNIROUTE_KEY_PATH", os.path.join(APP_DIR, "omniroute_key")
)
with open(private_key_path) as f:
private_key = f.read()
os.environ["GITHUB__DEPLOYMENT_TYPE"] = "app"
os.environ["GITHUB__APP_ID"] = os.environ.get("GITHUB_APP_ID", "4319749")
os.environ["GITHUB__PRIVATE_KEY"] = private_key
os.environ["GITHUB__WEBHOOK_SECRET"] = os.environ.get("GITHUB_WEBHOOK_SECRET", "")
with open(omni_key_path) as f:
omni_key = f.read().strip()
os.environ["OPENAI__API_BASE"] = os.environ.get(
"OPENAI_API_BASE", "https://omniroute.imrnes.team/v1"
)
os.environ["OPENAI__KEY"] = omni_key
os.environ["CONFIG__MODEL"] = os.environ.get("PR_AGENT_MODEL", "openai/claude-opus-4-8")
os.environ["CONFIG__FALLBACK_MODELS"] = os.environ.get(
"PR_AGENT_FALLBACK_MODELS",
'["openai/auto/best-coding","openai/auto/claude-sonnet"]',
)
os.environ["CONFIG__CUSTOM_MODEL_MAX_TOKENS"] = os.environ.get(
"PR_AGENT_MAX_TOKENS", "128000"
)
os.environ["GITHUB_APP__PR_COMMANDS"] = os.environ.get(
"PR_AGENT_PR_COMMANDS",
'["/review --pr_reviewer.require_score_review=true --pr_reviewer.require_security_review=true","/describe","/improve"]',
)
sys.path.insert(0, APP_DIR)
from pr_agent.servers.github_app import app as pr_agent_app, router as pr_router
from fastapi import FastAPI, Request
import uvicorn
import httpx
from starlette.middleware import Middleware
from starlette_context.middleware import RawContextMiddleware
app = FastAPI(middleware=[Middleware(RawContextMiddleware)])
app.include_router(pr_router)
@app.get("/setup/callback")
@app.post("/setup/callback")
async def callback(request: Request):
params = dict(request.query_params)
if "code" in params:
code = params["code"]
async with httpx.AsyncClient() as client:
resp = await client.post(
f"https://api.github.com/app-manifests/{code}/conversions",
headers={"Accept": "application/vnd.github.v3+json"},
)
if resp.status_code == 201:
data = resp.json()
creds = {
"app_id": data.get("id"),
"pem": data.get("pem"),
"webhook_secret": data.get("webhook_secret"),
"slug": data.get("slug"),
}
with open(os.path.join(APP_DIR, "credentials_callback.json"), "w") as f:
json.dump(creds, f, indent=2)
return {
"status": "success",
"app_id": creds["app_id"],
"slug": creds["slug"],
}
return {"status": "ok", "message": "callback received"}
@app.get("/health")
async def health():
return {"status": "ok"}
if __name__ == "__main__":
port = int(os.environ.get("PORT", "3000"))
print(f"PR-Agent GitHub App server starting...")
print(f" App ID: {os.environ.get('GITHUB_APP_ID', '')}")
print(f" Model: {os.environ.get('PR_AGENT_MODEL', 'openai/claude-opus-4-8')} via omniroute")
print(f" Endpoint: /api/v1/github_webhooks")
print(f" Port: {port}")
uvicorn.run(app, host="0.0.0.0", port=port, log_level="info")