diff --git a/.github/scripts/__tests__/bot-comment-handler.test.js b/.github/scripts/__tests__/bot-comment-handler.test.js index c3c14cb89..097a8bf7c 100644 --- a/.github/scripts/__tests__/bot-comment-handler.test.js +++ b/.github/scripts/__tests__/bot-comment-handler.test.js @@ -27,6 +27,8 @@ const REGISTRY_PATH = path.resolve(__dirname, '..', '..', 'agents', 'registry.ym test('default bot author allowlist recognizes canonical review bots', () => { for (const login of [ 'copilot[bot]', + 'copilot-pull-request-reviewer', + 'copilot-pull-request-reviewer[bot]', 'github-actions[bot]', 'coderabbitai[bot]', 'chatgpt-codex-connector', diff --git a/.github/scripts/bot-comment-handler.js b/.github/scripts/bot-comment-handler.js index 0331515a0..8e81fe73f 100644 --- a/.github/scripts/bot-comment-handler.js +++ b/.github/scripts/bot-comment-handler.js @@ -6,6 +6,8 @@ const MAX_CONTROLLER_COMMENT_LENGTH = 60000; const MAX_COLLECTED_COMMENT_OUTPUT_LENGTH = 450000; const DEFAULT_BOT_AUTHORS = Object.freeze([ 'copilot[bot]', + 'copilot-pull-request-reviewer', + 'copilot-pull-request-reviewer[bot]', 'github-actions[bot]', 'coderabbitai[bot]', 'chatgpt-codex-connector', diff --git a/.github/workflows/agents-bot-comment-handler.yml b/.github/workflows/agents-bot-comment-handler.yml index 7396d0917..75d5b0cc4 100644 --- a/.github/workflows/agents-bot-comment-handler.yml +++ b/.github/workflows/agents-bot-comment-handler.yml @@ -480,7 +480,7 @@ jobs: with: pr_number: ${{ needs.resolve.outputs.pr_number }} dry_run: ${{ inputs.dry_run == true }} - ignored_paths: '.agents/,scripts/langchain/prompts/,docs/,templates/' + ignored_paths: '.agents/,scripts/langchain/prompts/,docs/' secrets: service_bot_pat: ${{ secrets.SERVICE_BOT_PAT }} gh_app_client_id: ${{ secrets.WORKFLOWS_APP_CLIENT_ID }} diff --git a/.github/workflows/reusable-bot-comment-handler.yml b/.github/workflows/reusable-bot-comment-handler.yml index 199e80cce..b0dba60b0 100644 --- a/.github/workflows/reusable-bot-comment-handler.yml +++ b/.github/workflows/reusable-bot-comment-handler.yml @@ -38,7 +38,9 @@ on: required: false type: string default: >- - Copilot,copilot[bot],github-actions[bot],coderabbitai[bot], + Copilot,copilot[bot],copilot-pull-request-reviewer, + copilot-pull-request-reviewer[bot], + github-actions[bot],coderabbitai[bot], chatgpt-codex-connector,chatgpt-codex-connector[bot] skip_if_human_replied: description: 'Legacy option: skip active threads after any non-bot reply' @@ -68,7 +70,9 @@ on: required: false type: string default: >- - Copilot,copilot[bot],github-actions[bot],coderabbitai[bot], + Copilot,copilot[bot],copilot-pull-request-reviewer, + copilot-pull-request-reviewer[bot], + github-actions[bot],coderabbitai[bot], chatgpt-codex-connector,chatgpt-codex-connector[bot] skip_if_human_replied: description: 'Legacy option: skip active threads after any non-bot reply' diff --git a/docs/WORKFLOW_GUIDE.md b/docs/WORKFLOW_GUIDE.md index 4558c60ec..508ce5e56 100644 --- a/docs/WORKFLOW_GUIDE.md +++ b/docs/WORKFLOW_GUIDE.md @@ -161,7 +161,7 @@ _Inline Gate helper_ - **`reusable-20-pr-meta.yml`** — PR metadata/keepalive reusable for consumer repos. Dual-checks out the consumer repo + Workflows scripts, detects keepalive activations from comments/Gate runs, updates PR body sections, and dispatches the keepalive orchestrator using the provided PATs/default token (no App mint required). - **`reusable-70-orchestrator-init.yml`** — Preflight stage for Agents 70 orchestrator. Probes the load-balanced credential pool via `setup-api-client` + `checkRateLimitStatus` (fail-closed to `unknown` on probe errors), then repeats the gate on the exact wrapped client consumed by idle-precheck. Both gates preserve a 15% pool reserve plus forecast demand; the workflow exports the consuming `credential_pool_id` and `rate_limit_state` and resolves the remaining orchestrator parameters. - **`reusable-70-orchestrator-main.yml`** — Executes the orchestrator stages (keepalive gate, readiness, preflight, diagnostics, bootstrap, watchdog, keepalive sweep, belt scan/automerge) using the outputs from the init workflow. The belt scan creates one wrapped client, probes that exact client, and only then runs the scan through the same instance; unknown or under-reserve pools start no scan. Requires the GitHub App token when PATs aren’t available so keepalive writes still run under `agents-workflows-bot`. -- **`reusable-bot-comment-handler.yml`** — Collects the complete active, non-outdated bot `reviewThreads` set, generates an exact-head per-agent prompt, and persists the thread IDs and acceptance criteria in size-bounded controller comments. Immediately before the triggering assignment it re-queries both the head and complete active-thread set and fails closed for recollection if either changed. Manual callers retain `autofix:bot-comments` when that dispatch aborts, so a later event can recollect instead of losing the trigger. Human replies do not hide active review debt by default, uneditable comments from older credentials cannot block dispatch, and generic top-level reviews are not completion evidence. The handler prefers GitHub App client ID auth, records the selected App auth mode, keeps a warning-only legacy App ID fallback, and still falls back to `service_bot_pat` or `GITHUB_TOKEN` so consumer repos don’t have to configure extra secrets. +- **`reusable-bot-comment-handler.yml`** — Collects the complete active, non-outdated bot `reviewThreads` set, including GitHub Copilot's `copilot-pull-request-reviewer` identity variants, generates an exact-head per-agent prompt, and persists the thread IDs and acceptance criteria in size-bounded controller comments. Immediately before the triggering assignment it re-queries both the head and complete active-thread set and fails closed for recollection if either changed. Manual Workflows callers keep source-template review threads in scope and retain `autofix:bot-comments` when dispatch aborts, so a later event can recollect instead of losing the trigger. Human replies do not hide active review debt by default, uneditable comments from older credentials cannot block dispatch, and generic top-level reviews are not completion evidence. The handler prefers GitHub App client ID auth, records the selected App auth mode, keeps a warning-only legacy App ID fallback, and still falls back to `service_bot_pat` or `GITHUB_TOKEN` so consumer repos don’t have to configure extra secrets. - **`reusable-codex-run.yml`** — Codex execution wrapper that checks out the target PR branch, installs the pinned Codex CLI, runs the prompt, and pushes commits when the GitHub App token is available (otherwise drops to read-only mode using `GITHUB_TOKEN`). - **`reusable-model-profile-trial.yml`** — Dedicated read-only Codex trial worker. It executes an immutable helper checkout separately from the target, diff --git a/docs/bot-comment-handler.md b/docs/bot-comment-handler.md index b43663fbb..37d21e7c1 100644 --- a/docs/bot-comment-handler.md +++ b/docs/bot-comment-handler.md @@ -44,6 +44,8 @@ The workflow reads the PR's labels to determine which agent to use: By default, the workflow processes comments from: - `copilot[bot]` - GitHub Copilot code review +- `copilot-pull-request-reviewer` - GitHub Copilot pull-request review +- `copilot-pull-request-reviewer[bot]` - GitHub Copilot reviewer bot variant - `github-actions[bot]` - GitHub Actions (lint, type check suggestions) - `coderabbitai[bot]` - CodeRabbit AI review - `chatgpt-codex-connector` - Codex connector review diff --git a/templates/consumer-repo/.github/scripts/bot-comment-handler.js b/templates/consumer-repo/.github/scripts/bot-comment-handler.js index 0331515a0..8e81fe73f 100644 --- a/templates/consumer-repo/.github/scripts/bot-comment-handler.js +++ b/templates/consumer-repo/.github/scripts/bot-comment-handler.js @@ -6,6 +6,8 @@ const MAX_CONTROLLER_COMMENT_LENGTH = 60000; const MAX_COLLECTED_COMMENT_OUTPUT_LENGTH = 450000; const DEFAULT_BOT_AUTHORS = Object.freeze([ 'copilot[bot]', + 'copilot-pull-request-reviewer', + 'copilot-pull-request-reviewer[bot]', 'github-actions[bot]', 'coderabbitai[bot]', 'chatgpt-codex-connector', diff --git a/tests/workflows/test_bot_comment_handler.py b/tests/workflows/test_bot_comment_handler.py index 95711335e..e21359e62 100644 --- a/tests/workflows/test_bot_comment_handler.py +++ b/tests/workflows/test_bot_comment_handler.py @@ -19,9 +19,19 @@ def test_reusable_bot_comment_handler_ignores_agents_paths() -> None: assert ".agents/" in ignored_paths.split(",") bot_authors = inputs.get("bot_authors", {}).get("default", "") + assert "copilot-pull-request-reviewer" in bot_authors + assert "copilot-pull-request-reviewer[bot]" in bot_authors assert "chatgpt-codex-connector[bot]" in bot_authors +def test_canonical_bot_comment_handler_keeps_source_templates_in_scope() -> None: + workflow = _load_yaml(ROOT / ".github/workflows/agents-bot-comment-handler.yml") + ignored_paths = workflow["jobs"]["handle"]["with"]["ignored_paths"].split(",") + + assert ".agents/" in ignored_paths + assert "templates/" not in ignored_paths + + def test_reusable_bot_comment_handler_revalidates_active_threads_before_dispatch() -> None: workflow_path = ROOT / ".github/workflows/reusable-bot-comment-handler.yml" workflow = _load_yaml(workflow_path)