Skip to content

feat(web): add optional PR/MR summary comment to review agent#1175

Open
fatmcgav wants to merge 4 commits intosourcebot-dev:mainfrom
fatmcgav:feat-ai-codereview-summary-comment
Open

feat(web): add optional PR/MR summary comment to review agent#1175
fatmcgav wants to merge 4 commits intosourcebot-dev:mainfrom
fatmcgav:feat-ai-codereview-summary-comment

Conversation

@fatmcgav
Copy link
Copy Markdown
Contributor

@fatmcgav fatmcgav commented May 5, 2026

Summary

Adds an optional PR/MR summary comment to the AI Review Agent. When enabled, the agent generates a concise plain-text (with optional inline markdown) summary of the changes and posts it as a top-level comment on the PR/MR before pushing inline review comments.

  • New REVIEW_AGENT_SUMMARY_ENABLED env var (default: false) to opt in to summary comments
  • New REVIEW_AGENT_SUMMARY_MAX_LENGTH env var (default: 250) to control the maximum character length of the summary
  • New generatePrSummary node that calls the configured LLM with the PR title, description, and list of changed files to produce the summary; the result is hard-capped at REVIEW_AGENT_SUMMARY_MAX_LENGTH characters
  • GitHub: summary is posted as a top-level issue comment via octokit.rest.issues.createComment
  • GitLab: summary is posted as a general MR note via MergeRequestNotes.create
  • Summary generation errors are caught and logged so they never block inline review comments from being posted
  • Both new env vars are documented in review-agent.mdx and environment-variables.mdx, and added to .env.development and .devcontainer/docker-compose.yml

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • [Experimental] Added concise AI summary comments for pull/merge requests after reviews, toggleable and length-limited.
  • Documentation

    • Added environment variable docs for enabling summaries and setting max summary length; updated changelog.
  • Tests

    • Added tests covering summary creation, updates, and graceful failure handling for both platforms.

Adds REVIEW_AGENT_SUMMARY_ENABLED (default false) and REVIEW_AGENT_SUMMARY_MAX_LENGTH (default 250) env vars. When enabled, the review agent generates a concise markdown summary of the PR/MR changes and posts it as a top-level comment before pushing inline review comments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Walkthrough

Adds an experimental PR/MR summary feature to the Review Agent: two new env vars, a new summary-generation module that calls the AI text generator, wiring to conditionally produce a summary during PR/MR processing, and posting/updating summary comments on GitHub and GitLab.

Changes

PR/MR Summary Generation Feature

Layer / File(s) Summary
Environment Configuration
packages/shared/src/env.server.ts, .env.development, .devcontainer/docker-compose.yml
Introduces REVIEW_AGENT_SUMMARY_ENABLED (boolean, default false) and REVIEW_AGENT_SUMMARY_MAX_LENGTH (number, default 250).
Documentation / Changelog
CHANGELOG.md, docs/.../environment-variables.mdx, docs/.../review-agent.mdx
Adds changelog entry and documents the two new environment variables and their defaults.
Summary Generation
packages/web/src/features/agents/review-agent/nodes/generatePrSummary.ts
New generatePrSummary(prPayload) that selects a configured model, builds prompts from PR title/description/changed files, calls generateText, trims output to REVIEW_AGENT_SUMMARY_MAX_LENGTH, and returns the summary.
Coordinator / Flow
packages/web/src/features/agents/review-agent/app.ts
Adds generateSummarySafely(payload,label) (guarded by REVIEW_AGENT_SUMMARY_ENABLED), invokes it in GitHub PR and GitLab MR processing, and passes optional summary to push functions.
Platform Push Functions
packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts, .../gitlabPushMrReviews.ts
Updated signatures to accept summary?: string. If provided, post or update a PR comment on GitHub (issues API) or create/update an MR note on GitLab (MergeRequestNotes), with marker handling and error handling; existing inline review logic remains.
Tests
packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts, .../gitlabPushMrReviews.test.ts
Adds tests and enhanced mocks covering summary comment/note creation, updating existing summary marker note, and resilience when listing/creating comments fails.

Sequence Diagram

sequenceDiagram
    actor Agent as Review Agent
    participant Env as Env Config
    participant Gen as generatePrSummary
    participant AI as Language Model
    participant GH as GitHub API
    participant GL as GitLab API

    Agent->>Env: Check REVIEW_AGENT_SUMMARY_ENABLED
    alt enabled
        Agent->>Gen: generatePrSummary(prPayload)
        Gen->>AI: select model, send prompts
        AI-->>Gen: generated summary
        Gen->>Agent: truncated summary
        alt GitHub PR
            Agent->>GH: githubPushPrReviews(..., summary)
            GH-->>Agent: create/update issue comment
        else GitLab MR
            Agent->>GL: gitlabPushMrReviews(..., summary)
            GL-->>Agent: create/edit MR note
        end
    else disabled
        Agent->>Agent: skip summary generation
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sourcebot-dev/sourcebot#1104: Adds PR/MR summary generation and wires an optional summary parameter into GitHub/GitLab review publishing functions (directly related).

Suggested reviewers

  • brendan-kellam
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(web): add optional PR/MR summary comment to review agent' directly and clearly describes the primary feature added: an optional PR/MR summary comment capability for the review agent.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat-ai-codereview-summary-comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@fatmcgav fatmcgav marked this pull request as ready for review May 5, 2026 22:08
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/web/src/features/agents/review-agent/app.ts (1)

60-67: ⚡ Quick win

Extract duplicated summary generation into a helper.

Lines 60-67 and 85-92 are functionally identical aside from the log label ("PR" vs "MR"). Extracting a small helper keeps the two flows in sync if generation logic, error handling, or telemetry evolves later.

♻️ Proposed helper extraction
+async function generateSummaryIfEnabled(
+    prPayload: Parameters<typeof generatePrSummary>[0],
+    label: 'PR' | 'MR',
+): Promise<string | undefined> {
+    if (!env.REVIEW_AGENT_SUMMARY_ENABLED) {
+        return undefined;
+    }
+    try {
+        return await generatePrSummary(prPayload);
+    } catch (error) {
+        logger.error(`Error generating ${label} summary: ${error}`);
+        return undefined;
+    }
+}

Then replace the duplicated blocks with:

-    let summary: string | undefined;
-    if (env.REVIEW_AGENT_SUMMARY_ENABLED) {
-        try {
-            summary = await generatePrSummary(prPayload);
-        } catch (error) {
-            logger.error(`Error generating PR summary: ${error}`);
-        }
-    }
+    const summary = await generateSummaryIfEnabled(prPayload, 'PR');
-    let summary: string | undefined;
-    if (env.REVIEW_AGENT_SUMMARY_ENABLED) {
-        try {
-            summary = await generatePrSummary(prPayload);
-        } catch (error) {
-            logger.error(`Error generating MR summary: ${error}`);
-        }
-    }
+    const summary = await generateSummaryIfEnabled(prPayload, 'MR');

Also applies to: 85-92

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/features/agents/review-agent/app.ts` around lines 60 - 67,
Extract the duplicated PR/MR summary generation into a shared helper: create a
function (e.g., generateSummarySafely or generatePrOrMrSummary) that accepts the
payload and a label/tag ("PR" or "MR"), calls generatePrSummary(payload) inside
a try/catch, returns the summary (or undefined) and logs errors using
logger.error with the label included; then replace both duplicated blocks that
set summary (the one using generatePrSummary(prPayload) and the MR equivalent at
lines around 85-92) to call this new helper instead, preserving existing
behavior and telemetry/error handling.
packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts (1)

10-21: 🏗️ Heavy lift

Consider idempotency to avoid duplicate summary comments on re-run.

Each invocation unconditionally creates a new top-level issue comment. With REVIEW_AGENT_AUTO_REVIEW_ENABLED=true (or repeated review commands), the PR will accumulate one summary comment per run, which is more noticeable than for inline review comments since the summary is not anchored to a commit/line.

Consider tagging the comment with a hidden marker (e.g., <!-- sourcebot-review-summary -->) and, on subsequent runs, listing existing issue comments to find and updateComment it instead of creating a new one. The same pattern would apply to the GitLab MR notes flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts`
around lines 10 - 21, The current flow unconditionally calls
octokit.rest.issues.createComment with summary (using pr_payload) which creates
duplicate top-level comments on re-run; change this to be idempotent by first
listing existing issue comments via octokit.rest.issues.listComments (using
pr_payload.owner/repo/number), search for a comment containing a hidden marker
like "<!-- sourcebot-review-summary -->", and if found call
octokit.rest.issues.updateComment to replace its body, otherwise createComment
including the marker; keep error handling via logger.error as is for both
list/update/create operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 8-11: The Unreleased changelog entry is missing a subsection
header; move the bullet "- [Experimental] Added support for generating a summary
comment to the AI Code review agent. [`#1175`]..." under a new "### Added"
sub-header within the "## [Unreleased]" section so the entry is properly
parented per guidelines (add "### Added" immediately beneath "## [Unreleased]"
and keep the existing bullet under that header).

---

Nitpick comments:
In `@packages/web/src/features/agents/review-agent/app.ts`:
- Around line 60-67: Extract the duplicated PR/MR summary generation into a
shared helper: create a function (e.g., generateSummarySafely or
generatePrOrMrSummary) that accepts the payload and a label/tag ("PR" or "MR"),
calls generatePrSummary(payload) inside a try/catch, returns the summary (or
undefined) and logs errors using logger.error with the label included; then
replace both duplicated blocks that set summary (the one using
generatePrSummary(prPayload) and the MR equivalent at lines around 85-92) to
call this new helper instead, preserving existing behavior and telemetry/error
handling.

In `@packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts`:
- Around line 10-21: The current flow unconditionally calls
octokit.rest.issues.createComment with summary (using pr_payload) which creates
duplicate top-level comments on re-run; change this to be idempotent by first
listing existing issue comments via octokit.rest.issues.listComments (using
pr_payload.owner/repo/number), search for a comment containing a hidden marker
like "<!-- sourcebot-review-summary -->", and if found call
octokit.rest.issues.updateComment to replace its body, otherwise createComment
including the marker; keep error handling via logger.error as is for both
list/update/create operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 54e03067-c720-40b9-8e33-a1cd66c4c79b

📥 Commits

Reviewing files that changed from the base of the PR and between a6116ca and 1865c33.

📒 Files selected for processing (10)
  • .devcontainer/docker-compose.yml
  • .env.development
  • CHANGELOG.md
  • docs/docs/configuration/environment-variables.mdx
  • docs/docs/features/agents/review-agent.mdx
  • packages/shared/src/env.server.ts
  • packages/web/src/features/agents/review-agent/app.ts
  • packages/web/src/features/agents/review-agent/nodes/generatePrSummary.ts
  • packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts
  • packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.ts

Comment thread CHANGELOG.md
Gavin Williams and others added 2 commits May 5, 2026 23:19
…marySafely helper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ooter

GitHub and GitLab summary posting now checks for an existing comment/note
containing a hidden `<!-- sourcebot-review-summary -->` marker before writing.
If found, the existing comment is updated in place (`updateComment` /
`MergeRequestNotes.edit`); otherwise a new one is created, preventing
duplicate summary comments on re-runs.

A markdown footer is appended to every summary body showing
"Created: <timestamp>" on first post and "Updated: <timestamp>" on
subsequent runs, giving reviewers visibility into when the last review
was performed.

Tests:
* mock helpers updated to include `issues.listComments/createComment/
updateComment`` and `MergeRequestNotes.all/edit`.
* New test suites added for both GitHub and GitLab handlers covering:
  * no summary -> no API calls;
  * first post -> create with marker and "Created:" footer;
  * re-run -> update with "Updated:" footer and no duplicate create;
  * API failure -> no throw propagated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts`:
- Around line 13-20: The code uses octokit.rest.issues.listComments and then
searches for SUMMARY_MARKER which only checks the first page of comments; update
the logic to fetch all comment pages (e.g. use
octokit.paginate(octokit.rest.issues.listComments, { owner: pr_payload.owner,
repo: pr_payload.repo, issue_number: pr_payload.number })) and then run the
existing = comments.find(...) check against the full aggregated list so you
reliably detect an existing SUMMARY_MARKER and avoid duplicate creates; keep the
rest of the body/ action logic (SUMMARY_MARKER, action, body) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7bdeb1d4-5362-422d-900a-267e87c014cb

📥 Commits

Reviewing files that changed from the base of the PR and between 1865c33 and ff2c992.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • packages/web/src/features/agents/review-agent/app.ts
  • packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts
  • packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts
  • packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.test.ts
  • packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.ts
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

Comment on lines +13 to +20
const { data: comments } = await octokit.rest.issues.listComments({
owner: pr_payload.owner,
repo: pr_payload.repo,
issue_number: pr_payload.number,
});
const existing = comments.find(c => c.body?.includes(SUMMARY_MARKER));
const action = existing ? "Updated" : "Created";
const body = `${SUMMARY_MARKER}\n${summary}\n\n---\n*${action}: ${new Date().toUTCString()}*`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts

Repository: sourcebot-dev/sourcebot

Length of output: 3544


🌐 Web query:

octokit rest issues listComments pagination behavior

💡 Result:

For the Octokit REST endpoint that lists issue comments (GET /repos/{owner}/{repo}/issues/{issue_number}/comments), pagination works via GitHub’s standard REST pagination parameters (page, per_page) and the Link response header. Octokit’s pagination helpers follow that Link header. 1) REST endpoint (what Octokit is calling) - The endpoint supports per_page (max 100) and page, with defaults per_page=30 and page=1.[1] - Issue comments are ordered by ascending ID.[1] 2) How pagination is signaled (Link header) - When a response is paginated, GitHub includes a link header containing URLs for next/prev/first/last pages.[2] - If the endpoint does not support pagination or everything fits on one page, the link header is omitted.[2] 3) Octokit pagination behavior (what to expect in code) - Octokit’s REST pagination plugin (octokit.paginate from @octokit/plugin-paginate-rest) paginates “List …” endpoints by repeatedly issuing requests as long as a rel="next" URL is present in the response Link header.[3] - If the response lacks the Link header, octokit.paginate resolves with an array based on the single response.[3] 4) Practical pagination options - With the endpoint directly (octokit.rest.issues.listComments), set per_page and page yourself; per_page max is 100.[1] - With Octokit’s paginator, pass per_page=100 to reduce number of requests; it will continue automatically using rel="next" links.[3][1] 5) Small gotcha: streaming - An Octokit discussion indicates that streaming (custom Accept header / streaming assets) is not supported for listComments; use the normal JSON pagination approach instead.[4] Example usage (paginating all comments for an issue) - Iterate pages automatically: - const comments = await octokit.paginate(octokit.rest.issues.listComments, { owner, repo, issue_number, per_page: 100 }); (Relies on the Link header rel="next" mechanism described by the paginator plugin.[3])

Citations:


Fetch all issue-comment pages before deciding create vs. update.

octokit.rest.issues.listComments() returns only the first page (default 30 comments), so the existing lookup at line 18 can miss a summary comment on later pages. Use octokit.paginate(octokit.rest.issues.listComments, {...}) or manually iterate through pages to reliably find existing comments and avoid creating duplicates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.ts`
around lines 13 - 20, The code uses octokit.rest.issues.listComments and then
searches for SUMMARY_MARKER which only checks the first page of comments; update
the logic to fetch all comment pages (e.g. use
octokit.paginate(octokit.rest.issues.listComments, { owner: pr_payload.owner,
repo: pr_payload.repo, issue_number: pr_payload.number })) and then run the
existing = comments.find(...) check against the full aggregated list so you
reliably detect an existing SUMMARY_MARKER and avoid duplicate creates; keep the
rest of the body/ action logic (SUMMARY_MARKER, action, body) unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant