Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- [EE] Added prompt caching for Ask Sourcebot. For Anthropic models, the static prompt prefix (tool definitions, system prompt, and conversation history) is marked with a cache breakpoint so it is billed at the provider's discounted cache-read rate on subsequent agent steps and follow-up turns. Toggle with `SOURCEBOT_CHAT_PROMPT_CACHING_ENABLED` (default `true`). [#1278](https://github.com/sourcebot-dev/sourcebot/pull/1278)
- [EE] Added a cached-token breakdown to the Ask Sourcebot message details, showing what share of the input tokens were served from the model provider's prompt cache. [#1278](https://github.com/sourcebot-dev/sourcebot/pull/1278)
- [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
- Upgraded `protobufjs` to `^7.6.2`. [#1281](https://github.com/sourcebot-dev/sourcebot/pull/1281)
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 @@ -68,11 +68,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> |
Comment thread
fatmcgav marked this conversation as resolved.
| `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 @@ -240,10 +240,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}`); },
);
};

// eslint-disable-next-line authz/require-auth-wrapper -- authenticated via GitHub App / GitLab webhook secrets, not user session
export const POST = async (request: NextRequest) => {
const body = await request.json();
Expand Down Expand Up @@ -186,6 +196,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 @@ -247,6 +268,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