Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- [Experimental] Review agent now acknowledges receipt of the `review` command by adding a reaction to the triggering comment. The reaction is configurable via `REVIEW_AGENT_ACK_REACTION` (default: `eyes`). [#1174](https://github.com/sourcebot-dev/sourcebot/pull/1174)

### Fixed
- Add missing schema changes introduced in [#1170](https://github.com/sourcebot-dev/sourcebot/pull/1170). [#1176](https://github.com/sourcebot-dev/sourcebot/pull/1176)
- Fixed blame gutter commit navigation to use the file path as it existed at the attributing commit, so clicking a blame line whose commit predates a rename resolves to the correct historical path. [#1178](https://github.com/sourcebot-dev/sourcebot/pull/1178)
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/configuration/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ The following environment variables allow you to configure your Sourcebot deploy
| `GITHUB_REVIEW_AGENT_APP_PRIVATE_KEY_PATH` | `-` | <p>The container relative path to the private key file for the GitHub App used by the review agent.</p> |
| `GITHUB_REVIEW_AGENT_APP_WEBHOOK_SECRET` | `-` | <p>The webhook secret for the GitHub App used by the review agent.</p> |
| `OPENAI_API_KEY` | `-` | <p>The OpenAI API key used by the review agent.</p> |
| `REVIEW_AGENT_ACK_REACTION` | `eyes` | <p>The reaction/emoji added to a comment when the review agent acknowledges receipt of the review command.</p> |
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 | 🟡 Minor | ⚡ Quick win

Wrap the default value in inline code.

The default value eyes is rendered as plain text, while every other entry in the table uses backtick-wrapped inline code for default values (e.g., `false`, `true`, `review`). This is also inconsistent with the coding guidelines for .mdx files.

📝 Proposed fix
-| `REVIEW_AGENT_ACK_REACTION` | `eyes` | <p>The reaction/emoji added to a comment when the review agent acknowledges receipt of the review command.</p> |
+| `REVIEW_AGENT_ACK_REACTION` | `eyes` | <p>The reaction/emoji added to a comment when the review agent acknowledges receipt of the review command.</p> |

Specifically, change the default column from eyes (unquoted) to `eyes`.

As per coding guidelines: "use inline code for technical values."

🤖 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 `@docs/docs/configuration/environment-variables.mdx` at line 73, Update the
table row for REVIEW_AGENT_ACK_REACTION so the default value is formatted as
inline code; change the Default column from plain eyes to backtick-wrapped
`eyes` (edit the table entry that references REVIEW_AGENT_ACK_REACTION to use
`eyes`).

| `REVIEW_AGENT_API_KEY` | `-` | <p>The Sourcebot API key used by the review agent.</p> |
| `REVIEW_AGENT_AUTO_REVIEW_ENABLED` | `false` | <p>Enables/disables automatic code reviews by the review agent.</p> |
| `REVIEW_AGENT_LOGGING_ENABLED` | `true` | <p>Enables/disables logging for the review agent. Logs are saved in `DATA_CACHE_DIR/review-agent`</p> |
| `REVIEW_AGENT_REVIEW_COMMAND` | `review` | <p>The command used to trigger a code review by the review agent.</p> |

### Overriding environment variables from the config

You can override environment variables from the config file by using the `environmentOverrides` property. See [this doc](/docs/configuration/config-file#overriding-environment-variables-from-the-config) for more info.
You can override environment variables from the config file by using the `environmentOverrides` property. See [this doc](/docs/configuration/config-file#overriding-environment-variables-from-the-config) for more info.
5 changes: 3 additions & 2 deletions docs/docs/features/agents/review-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ You can also trigger a review manually by commenting `/review` on any PR or MR.

| Variable | Default | Description |
|---|---|---|
| `REVIEW_AGENT_ACK_REACTION` | `eyes` | Reaction/emoji added to acknowledge receipt of the review command |
| `REVIEW_AGENT_AUTO_REVIEW_ENABLED` | `false` | Automatically review new and updated PRs/MRs |
| `REVIEW_AGENT_REVIEW_COMMAND` | `review` | Comment command that triggers a manual review (without the `/`) |
| `REVIEW_AGENT_MODEL` | first configured model | `displayName` of the language model to use for reviews |
| `REVIEW_AGENT_LOGGING_ENABLED` | unset | Write prompt and response logs to disk for debugging |
| `REVIEW_AGENT_MODEL` | first configured model | `displayName` of the language model to use for reviews |
| `REVIEW_AGENT_REVIEW_COMMAND` | `review` | Comment command that triggers a manual review (without the `/`) |
5 changes: 3 additions & 2 deletions packages/shared/src/env.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,11 @@ const options = {
GITLAB_REVIEW_AGENT_TOKEN: z.string().optional(),
GITLAB_REVIEW_AGENT_HOST: z.string().default('gitlab.com').transform(s => s.replace(/^https?:\/\//, '').replace(/\/+$/, '')).refine(s => /^[a-z0-9.-]+$/i.test(s), { message: 'invalid hostname' }),
// Review agent config
REVIEW_AGENT_MODEL: z.string().optional(),
REVIEW_AGENT_ACK_REACTION: z.string().default('eyes'),
REVIEW_AGENT_API_KEY: z.string().optional(),
REVIEW_AGENT_LOGGING_ENABLED: booleanSchema.default('true'),
REVIEW_AGENT_AUTO_REVIEW_ENABLED: booleanSchema.default('false'),
REVIEW_AGENT_LOGGING_ENABLED: booleanSchema.default('true'),
REVIEW_AGENT_MODEL: z.string().optional(),
REVIEW_AGENT_REVIEW_COMMAND: z.string().default('review'),

ANTHROPIC_API_KEY: z.string().optional(),
Expand Down
31 changes: 31 additions & 0 deletions packages/web/src/app/api/(server)/webhook/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ if (env.GITLAB_REVIEW_AGENT_TOKEN) {
}
}

const ACK_TIMEOUT_MS = 1500;

const ackWithTimeout = (promise: Promise<unknown>, label: string): Promise<void> => {
const timeout = new Promise<void>(resolve => setTimeout(resolve, ACK_TIMEOUT_MS));
return Promise.race([promise, timeout]).then(
() => { /* success or timeout — proceed */ },
(error) => { logger.warn(`${label}: ${error}`); },
);
};

export const POST = async (request: NextRequest) => {
const body = await request.json();
const headers = Object.fromEntries(Array.from(request.headers.entries(), ([key, value]) => [key.toLowerCase(), value]));
Expand Down Expand Up @@ -185,6 +195,17 @@ export const POST = async (request: NextRequest) => {
const owner = body.repository.owner.login;

const octokit = await githubApp.getInstallationOctokit(body.installation.id);

await ackWithTimeout(
octokit.rest.reactions.createForIssueComment({
owner,
repo: repositoryName,
comment_id: body.comment.id,
content: env.REVIEW_AGENT_ACK_REACTION as "-1" | "+1" | "laugh" | "confused" | "heart" | "hooray" | "rocket" | "eyes",
}),
'Failed to add acknowledgment reaction to GitHub comment',
);

const { data: pullRequest } = await octokit.rest.pulls.get({
owner,
repo: repositoryName,
Expand Down Expand Up @@ -246,6 +267,16 @@ export const POST = async (request: NextRequest) => {
if (noteBody === `/${env.REVIEW_AGENT_REVIEW_COMMAND}`) {
logger.info('Review agent review command received on GitLab MR, processing');

await ackWithTimeout(
gitlabClient.MergeRequestNoteAwardEmojis.award(
parsed.data.project.id,
parsed.data.merge_request.iid,
parsed.data.object_attributes.id,
env.REVIEW_AGENT_ACK_REACTION,
),
'Failed to add acknowledgment emoji to GitLab note',
);

const mrPayload: GitLabMergeRequestPayload = {
object_kind: "merge_request",
object_attributes: {
Expand Down
1 change: 1 addition & 0 deletions packages/web/src/features/agents/review-agent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export type GitLabMergeRequestPayload = z.infer<typeof gitLabMergeRequestPayload
export const gitLabNotePayloadSchema = z.object({
object_kind: z.literal('note'),
object_attributes: z.object({
id: z.number(),
note: z.string(),
noteable_type: z.literal('MergeRequest'),
}),
Expand Down
Loading