From c0eee9c0f66baba7c708f059138e292dd220ba20 Mon Sep 17 00:00:00 2001 From: Abir Abbas Date: Mon, 11 May 2026 15:08:22 -0400 Subject: [PATCH] refactor: simplify env var surface; align on SWE-AF naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pr-af shared three legacy env-var aliases with its newer canonical names. They've been side-by-side for a while; this drops the legacy side now that nothing reads them. **Removed (with the still-supported replacement):** - `HARNESS_PROVIDER` → `PR_AF_PROVIDER` - `HARNESS_MODEL` → `PR_AF_MODEL` - `AI_MODEL` / `PR_AF_AI_MODEL` → `PR_AF_MODEL` (the .ai() / .harness() splits both fall back to the same value; per-tier overrides via `PR_AF_MODEL_BUDGET` / `_MID` / `_PREMIUM` are unchanged) - `OPENCODE_SERVER` → `PR_AF_OPENCODE_SERVER` - `GITHUB_TOKEN` → `GH_TOKEN` (matches SWE-AF, the public release with the most users — github-buddy is being aligned in parallel) **Also fixes a latent typo:** `NODE_ID` was being read as `PR_AF` (`os.getenv("PR_AF", "pr-af")` at app.py:27). The `PR_AF` env var is never set anywhere, so pr-af's registered node id always silently defaulted to `"pr-af"` regardless of any deployer's intent. Now reads `NODE_ID` like the other agents on the stack. Dockerfile + docker-compose updated to match. README + docs/DX.md references to `GITHUB_TOKEN` (as a description of pr-af's own env var) updated to `GH_TOKEN`. References to GitHub Actions' built-in `secrets.GITHUB_TOKEN` are unchanged — that's a GitHub-side convention we don't control. Co-Authored-By: Claude Opus 4.7 (1M context) --- Dockerfile | 5 ++--- README.md | 2 +- docker-compose.yml | 6 ++---- docs/DX.md | 4 ++-- src/pr_af/app.py | 4 ++-- src/pr_af/config.py | 16 ++++------------ src/pr_af/github/client.py | 4 ++-- 7 files changed, 15 insertions(+), 26 deletions(-) diff --git a/Dockerfile b/Dockerfile index 272f27a..c2b6ad8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,9 +29,8 @@ FROM python:3.11-slim AS runtime ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ AGENTFIELD_SERVER=http://agentfield:8080 \ - HARNESS_PROVIDER=opencode \ - HARNESS_MODEL=openrouter/moonshotai/kimi-k2.5 \ - AI_MODEL=openrouter/moonshotai/kimi-k2.5 \ + PR_AF_PROVIDER=opencode \ + PR_AF_MODEL=openrouter/moonshotai/kimi-k2.5 \ PORT=8004 \ HOME=/home/praf \ PYTHONPATH=/app/src \ diff --git a/README.md b/README.md index 3b3c5e3..80fa9f0 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ There are excellent AI code review tools on the market. PR-AF is not designed to ```bash git clone https://github.com/Agent-Field/pr-af.git && cd pr-af -cp .env.example .env # Add OPENROUTER_API_KEY, GITHUB_TOKEN +cp .env.example .env # Add OPENROUTER_API_KEY, GH_TOKEN docker compose up --build ``` diff --git a/docker-compose.yml b/docker-compose.yml index f2db403..92ef035 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,11 +22,9 @@ services: - AGENTFIELD_SERVER=http://agentfield:8080 - AGENTFIELD_API_KEY=${AGENTFIELD_API_KEY:-} - AGENT_CALLBACK_URL=http://pr-af:8004 - - HARNESS_PROVIDER=opencode - - HARNESS_MODEL=${HARNESS_MODEL:-openrouter/moonshotai/kimi-k2.5} - - AI_MODEL=${AI_MODEL:-openrouter/moonshotai/kimi-k2.5} + - PR_AF_PROVIDER=${PR_AF_PROVIDER:-opencode} + - PR_AF_MODEL=${PR_AF_MODEL:-openrouter/moonshotai/kimi-k2.5} - OPENROUTER_API_KEY=${OPENROUTER_API_KEY} - - GITHUB_TOKEN=${GITHUB_TOKEN:-} - GH_TOKEN=${GH_TOKEN:-} - XDG_DATA_HOME=/home/praf/.local/share - PR_AF_WORKDIR=/workspaces diff --git a/docs/DX.md b/docs/DX.md index dca0401..25271fe 100644 --- a/docs/DX.md +++ b/docs/DX.md @@ -33,7 +33,7 @@ POST /api/v1/execute/async/pr-af.review - Configurable: `--clone` (full clone), `--shallow` (depth=1), `--no-clone` (API only) **Authentication:** -- `GITHUB_TOKEN` env var (personal access token or GitHub App installation token) +- `GH_TOKEN` env var (personal access token or GitHub App installation token) - GitHub App: preferred for CI/CD (fine-grained permissions, higher rate limits) **Best for:** CI/CD pipelines, GitHub Action triggers, full-featured review. @@ -369,7 +369,7 @@ comments: | Variable | Required | Description | |---|---|---| -| `GITHUB_TOKEN` | Yes (for GitHub output) | GitHub PAT or App installation token | +| `GH_TOKEN` | Yes (for GitHub output) | GitHub PAT or App installation token | | `AGENTFIELD_API_KEY` | Yes | AgentField platform API key | | `OPENROUTER_API_KEY` | Yes | LLM provider API key | | `PR_AF_CONFIG` | No | Path to config file (default: `.pr-af.yml`) | diff --git a/src/pr_af/app.py b/src/pr_af/app.py index 1612e5c..2c05c9c 100644 --- a/src/pr_af/app.py +++ b/src/pr_af/app.py @@ -24,7 +24,7 @@ load_dotenv(_project_root / ".env") _ai_config = AIIntegrationConfig.from_env() -NODE_ID = os.getenv("PR_AF", "pr-af") +NODE_ID = os.getenv("NODE_ID", "pr-af") HarnessConfig = _agentfield.HarnessConfig app = Agent( @@ -95,7 +95,7 @@ def _resolve_repo(repo_path: str | None, pr_url: str | None) -> str: os.makedirs(workdir, exist_ok=True) clone_url = target - gh_token = os.getenv("GH_TOKEN") or os.getenv("GITHUB_TOKEN", "") + gh_token = os.getenv("GH_TOKEN", "") if gh_token and clone_url.startswith("https://github.com/"): clone_url = clone_url.replace("https://github.com/", f"https://{gh_token}@github.com/") diff --git a/src/pr_af/config.py b/src/pr_af/config.py index e4f07e4..4f87018 100644 --- a/src/pr_af/config.py +++ b/src/pr_af/config.py @@ -238,17 +238,12 @@ def from_yaml(cls, path: str) -> ReviewConfig: class AIIntegrationConfig(BaseModel): - provider: str = Field( - default_factory=lambda: os.getenv("PR_AF_PROVIDER", os.getenv("HARNESS_PROVIDER", "opencode")) - ) + provider: str = Field(default_factory=lambda: os.getenv("PR_AF_PROVIDER", "opencode")) harness_model: str = Field( - default_factory=lambda: os.getenv("PR_AF_MODEL", os.getenv("HARNESS_MODEL", "minimax/minimax-m2.5")) + default_factory=lambda: os.getenv("PR_AF_MODEL", "minimax/minimax-m2.5") ) ai_model: str = Field( - default_factory=lambda: os.getenv( - "PR_AF_AI_MODEL", - os.getenv("AI_MODEL", os.getenv("PR_AF_MODEL", "minimax/minimax-m2.5")), - ) + default_factory=lambda: os.getenv("PR_AF_MODEL", "minimax/minimax-m2.5") ) max_turns: int = Field(default_factory=lambda: int(os.getenv("PR_AF_MAX_TURNS", "50"))) max_retries: int = Field(default_factory=lambda: int(os.getenv("PR_AF_AI_MAX_RETRIES", "3"))) @@ -257,9 +252,7 @@ class AIIntegrationConfig(BaseModel): ) max_backoff_seconds: float = Field(default_factory=lambda: float(os.getenv("PR_AF_AI_MAX_BACKOFF_SECONDS", "8.0"))) opencode_bin: str = Field(default_factory=lambda: os.getenv("PR_AF_OPENCODE_BIN", "opencode")) - opencode_server: str | None = Field( - default_factory=lambda: os.getenv("PR_AF_OPENCODE_SERVER", os.getenv("OPENCODE_SERVER")) - ) + opencode_server: str | None = Field(default_factory=lambda: os.getenv("PR_AF_OPENCODE_SERVER")) @classmethod def from_env(cls) -> AIIntegrationConfig: @@ -271,7 +264,6 @@ def provider_env(self) -> dict[str, str]: "ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GOOGLE_API_KEY", - "GITHUB_TOKEN", "GH_TOKEN", ) env: dict[str, str] = {key: value for key in env_keys if (value := os.getenv(key))} diff --git a/src/pr_af/github/client.py b/src/pr_af/github/client.py index 19fd8a3..3b9b6dc 100644 --- a/src/pr_af/github/client.py +++ b/src/pr_af/github/client.py @@ -85,7 +85,7 @@ def _is_github_app_configured() -> bool: class GitHubClient: def __init__(self, token: str | None = None): - self.token = token or os.getenv("GITHUB_TOKEN", "") + self.token = token or os.getenv("GH_TOKEN", "") self.base_url = "https://api.github.com" self._use_app_auth = _is_github_app_configured() @@ -262,7 +262,7 @@ async def clone_repo( if self._use_app_auth: token = await _get_installation_token(owner, repo) else: - token = os.getenv("GH_TOKEN") or self.token or os.getenv("GITHUB_TOKEN", "") + token = os.getenv("GH_TOKEN") or self.token if not token: raise ValueError("GitHub token is required for clone_repo")