| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting. Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds GitLab Merge Request support to the review agent: env schema and client, webhook routing/validation for GitLab events, MR parsing and posting, UI split for GitHub/GitLab agents, AI SDK model selection, repo-scoped file source API, tests, dependency and docs/changelog updates. Changes
Sequence DiagramsequenceDiagram
participant User as User
participant Webhook as Webhook Handler
participant GitLab as GitLab API
participant Parser as MR Parser
participant LLM as LLM Service
participant Pusher as MR Pusher
User->>Webhook: POST GitLab webhook (MR or note)
Webhook->>Webhook: validate x-gitlab-token vs GITLAB_REVIEW_AGENT_WEBHOOK_SECRET
Webhook->>GitLab: MergeRequests.show(projectId, mrIid)
GitLab-->>Webhook: MR details
Webhook->>Parser: gitlabMrParser(client, payload)
Parser->>GitLab: MergeRequests.allDiffs(projectId, mrIid)
GitLab-->>Parser: file diffs
Parser-->>Webhook: parsed PR payload (with file_diffs, diff_refs)
Webhook->>LLM: generatePrReviews(prPayload)
LLM-->>Webhook: review items per file
Webhook->>Pusher: gitlabPushMrReviews(client, projectId, prPayload, reviews)
Pusher->>GitLab: MergeRequestDiscussions.create (inline)
alt inline succeeds
GitLab-->>Pusher: discussion created
else inline fails
Pusher->>GitLab: MergeRequestNotes.create (fallback note)
GitLab-->>Pusher: note created
end
Pusher-->>Webhook: done
Webhook-->>User: { status: "ok" }
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labelssourcebot-team Suggested reviewers
❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches 🧪 Generate unit tests (beta)
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. ❤️ ShareComment @coderabbitai help to get the list of available commands and usage tips. |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (7)packages/web/src/features/git/getFileSourceApi.ts (1)🤖 Prompt for all review comments with AI agentspackages/web/src/app/(app)/agents/page.tsx (1)10-10: Prefer import type for purely type-level imports.
Org and PrismaClient are only used in type positions here.
Suggested cleanup🤖 Prompt for AI Agents-import { Org, PrismaClient } from '@sourcebot/db'; +import type { Org, PrismaClient } from '@sourcebot/db';Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/git/getFileSourceApi.ts` at line 10, The import currently brings in Org and PrismaClient as runtime imports even though they are only used as types; change the import in getFileSourceApi.ts to a type-only import by replacing "import { Org, PrismaClient } from '@sourcebot/db';" with "import type { Org, PrismaClient } from '@sourcebot/db';" and ensure no runtime references to Org or PrismaClient remain so the type-only import is valid.packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts (1)30-42: Single-agent layout branches are now dead code.
Since agents is statically two entries, the agents.length === 1 conditionals are no longer reachable and can be simplified.
🤖 Prompt for AI AgentsVerify each finding against the current code and only fix it if needed. In `@packages/web/src/app/`(app)/agents/page.tsx around lines 30 - 42, The conditional branches checking agents.length === 1 are dead code; simplify the layout by removing the single-agent branches and using the multi-agent classes directly for the container and the agent card. Update the outer container JSX (where agents.map is rendered) to always use "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10" and update the agent card JSX (the div with key={agent.id} and className logic) to always use the multi-agent class "relative flex flex-col items-center border border-border rounded-2xl p-8 bg-card shadow-xl" so the unnecessary ternary checks around agents.length are eliminated.packages/web/src/features/agents/review-agent/app.ts (1)13-18: Avoid re-querying the org on every file fetch call.
fetchFileContent is called repeatedly per diff, so this org lookup is repeated unnecessarily. Consider resolving org once upstream and passing it down.
🤖 Prompt for AI AgentsVerify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts` around lines 13 - 18, The org lookup inside fetchFileContent (currently using __unsafePrisma.org.findUnique with SINGLE_TENANT_ORG_ID and throwing if org is missing) causes repeated DB queries; refactor fetchFileContent to accept an org (or orgId/needed org fields) as an argument and remove the internal __unsafePrisma.org.findUnique call so callers resolve org once upstream and pass it in, or alternatively add a lightweight in-memory cache keyed by SINGLE_TENANT_ORG_ID and reuse the cached org instead of re-querying each call.packages/web/src/app/api/(server)/webhook/route.ts (2)62-80: Consider extracting duplicate log setup logic.
The log path initialization (directory creation, timestamp formatting, path construction) is duplicated between processGitHubPullRequest (lines 29-47) and processGitLabMergeRequest (lines 62-80). This could be extracted to a shared helper.
♻️ Example helper extraction🤖 Prompt for AI Agentsfunction getReviewAgentLogPath(identifier: string): string | undefined { if (!env.REVIEW_AGENT_LOGGING_ENABLED) { return undefined; } const reviewAgentLogDir = path.join(env.DATA_CACHE_DIR, "review-agent"); if (!fs.existsSync(reviewAgentLogDir)) { fs.mkdirSync(reviewAgentLogDir, { recursive: true }); } const timestamp = new Date().toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/(\d+)\/(\d+)\/(\d+), (\d+):(\d+):(\d+)/, '$3_$1_$2_$4_$5_$6'); const logPath = path.join(reviewAgentLogDir, `review-agent-${identifier}-${timestamp}.log`); logger.info(`Review agent logging to ${logPath}`); return logPath; }Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/app.ts` around lines 62 - 80, Extract the duplicated log setup in processGitHubPullRequest and processGitLabMergeRequest into a single helper (e.g., getReviewAgentLogPath(identifier)) that checks env.REVIEW_AGENT_LOGGING_ENABLED, ensures the review-agent directory exists (fs.existsSync + fs.mkdirSync with recursive), builds the timestamp using the same toLocaleString/replace logic, composes the filename with the provided identifier (replace uses of mrPayload.object_attributes.iid or pullRequest number), calls logger.info with the final path, and returns the path or undefined; then replace the duplicate blocks in both functions with a call to this helper.packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts (1)246-252: Same error handling concern for note event processing.
Apply similar try-catch wrapping here to prevent webhook retry storms on processing errors.
♻️ Suggested error handling🤖 Prompt for AI Agents+ try { await processGitLabMergeRequest( gitlabClient, body.project.id, mrPayload, env.GITLAB_REVIEW_AGENT_HOST, ); + } catch (error) { + logger.error('Error processing GitLab note event:', error); + }Verify each finding against the current code and only fix it if needed. In `@packages/web/src/app/api/`(server)/webhook/route.ts around lines 246 - 252, Wrap the call to processGitLabMergeRequest in a try-catch to mirror the note-event handling: invoke await processGitLabMergeRequest(gitlabClient, body.project.id, mrPayload, env.GITLAB_REVIEW_AGENT_HOST) inside try, and on catch log the error with context (including body.project.id and event type) and return a successful webhook response so GitLab doesn't retry; ensure you reference processGitLabMergeRequest, gitlabClient, mrPayload and env.GITLAB_REVIEW_AGENT_HOST when adding the logging/context.
220-226: Consider wrapping processGitLabMergeRequest in try-catch to prevent retry storms.
If processGitLabMergeRequest throws, the webhook returns a 500 error, which may cause GitLab to retry the webhook delivery repeatedly. This could lead to duplicate review attempts or excessive load.
♻️ Suggested error handling🤖 Prompt for AI Agentsif (isGitLabMergeRequestEvent(gitlabEvent, body)) { if (env.REVIEW_AGENT_AUTO_REVIEW_ENABLED === "false") { logger.info('Review agent auto review (REVIEW_AGENT_AUTO_REVIEW_ENABLED) is disabled, skipping'); return Response.json({ status: 'ok' }); } + try { await processGitLabMergeRequest( gitlabClient, body.project.id, body, env.GITLAB_REVIEW_AGENT_HOST, ); + } catch (error) { + logger.error('Error processing GitLab merge request:', error); + } }Verify each finding against the current code and only fix it if needed. In `@packages/web/src/app/api/`(server)/webhook/route.ts around lines 220 - 226, Wrap the call to processGitLabMergeRequest(gitlabClient, body.project.id, body, env.GITLAB_REVIEW_AGENT_HOST) in a try-catch inside the webhook route handler; on error catch the exception, log the full error (including contextual values like body.project.id and env.GITLAB_REVIEW_AGENT_HOST) using the existing logger (or console.error if none), and return a non-retriable HTTP response (e.g., 200/202 with an error payload) instead of letting the exception bubble up to produce a 500. Ensure the catch only suppresses delivery retries while still surfacing enough detail in logs for debugging.35-41: Consider swapping system and prompt content for better provider compatibility.
The detailed review prompt is placed in system while the user turn only contains "Review the code changes." This inverted usage may cause suboptimal results with some providers that expect the system message to contain role/behavior instructions and the user message to contain the actual task content.
♻️ Suggested refactor🤖 Prompt for AI Agentsconst result = await generateText({ model, - system: prompt, - prompt: "Review the code changes.", + system: "You are a code review assistant. Respond only with valid JSON matching the expected schema.", + prompt: prompt, providerOptions, temperature, });Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts` around lines 35 - 41, The generateText call in invokeDiffReviewLlm.ts currently passes the detailed review instructions in the system parameter and a generic "Review the code changes." as the prompt, which can confuse some providers; update the call to use a concise role/behavior string for system (e.g., a short reviewer persona) and pass the detailed review text stored in the prompt variable as the prompt/user message instead. Modify the generateText invocation (function generateText, params model, system, prompt, providerOptions, temperature) so system contains role/behavior guidance and prompt is the detailed review instructions currently in the prompt variable, keeping providerOptions and temperature unchanged.
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/shared/src/env.server.ts`:
- Around line 198-202: The GITLAB_REVIEW_AGENT_HOST env entry currently accepts
any string which can include a protocol and break the later `https://${...}` URL
assembly; update the env schema for GITLAB_REVIEW_AGENT_HOST in
packages/shared/src/env.server.ts (the env schema definition) to
validate/normalize it as a hostname: replace the current
z.string().default('gitlab.com') with a schema that strips any leading
protocol/slashes and validates the remainder as a hostname (e.g., use
z.string().default('gitlab.com').transform(s => s.replace(/^https?:\/\//,
'').replace(/\/+$/, '')).refine(s => /^[a-z0-9.-]+$/i.test(s), { message:
'invalid hostname' })), so downstream code that constructs
`https://${GITLAB_REVIEW_AGENT_HOST}` always receives a bare hostname.
In `@packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts`:
- Around line 21-27: fileSourceRequest currently omits the Git ref so
getFileSourceForRepo may read the default branch; add a ref property to
fileSourceRequest set to the PR/MR head SHA (the head SHA variable available in
this scope) before calling getFileSourceForRepo so the fetch uses the exact
revision under review; update the object passed to getFileSourceForRepo
(fileSourceRequest) to include ref and ensure you pass the same org and
__unsafePrisma options.
In
`@packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts`:
- Around line 133-139: The async test "does not throw when all review comments
fail" incorrectly uses resolves.not.toThrow(); update the assertion to await
that the promise resolves to undefined by replacing the matcher with
resolves.toBeUndefined() when calling githubPushPrReviews(octokit, MOCK_PAYLOAD,
SINGLE_REVIEW) so the test correctly asserts the resolved value; locate the test
block containing githubPushPrReviews and change the expectation accordingly.
In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts`:
- Around line 99-101: The code in gitlabMrParser.ts currently force-casts
mr.diff_refs to a typed object when building the MR payload
(head_sha/diff_refs), which can throw if mr.diff_refs is null; update the logic
in the function that constructs the object (where mr.diff_refs is accessed) to
first validate mr.diff_refs !== null && mr.diff_refs !== undefined before the
type assertion, and if missing, set diff_refs to undefined or an empty safe
fallback and ensure head_sha is derived from mr.sha or guarded similarly so
downstream gitlabPushMrReviews can gracefully fall back to general notes; this
avoids runtime errors by failing over rather than force-casting a potentially
null value.
In `@packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.ts`:
- Around line 29-38: The position object sent to GitLab is using camelCase and
wrong types; update the object in gitlabPushMrReviews.ts (the position block
that references base_sha, head_sha, start_sha, fileDiffReview.filename and
review.line_end) to use GitLab's snake_case keys: position_type, base_sha,
head_sha, start_sha, new_path and include old_path (set to
fileDiffReview.filename), and ensure new_line is a number (use review.line_end
as a number, not String). Preserve the surrounding structure but replace
camelCase keys (baseSha, headSha, startSha, newPath, newLine) with the correct
snake_case ones so `@gitbeaker/rest` forwards a valid GitLab API payload.
In `@packages/web/src/features/agents/review-agent/types.ts`:
- Around line 59-74: The GitLab webhook interfaces assume diff_refs is always
present, which is unsafe; update
GitLabMergeRequestPayload.object_attributes.diff_refs and
GitLabNotePayload.merge_request.diff_refs to be optional or nullable (e.g., mark
as diff_refs?: { base_sha: string; head_sha: string; start_sha: string } | null)
so downstream code must handle missing/null diff_refs; adjust any related type
imports/exports if necessary and run type checks to ensure no remaining non-null
assumptions.
---
Nitpick comments:
In `@packages/web/src/app/`(app)/agents/page.tsx:
- Around line 30-42: The conditional branches checking agents.length === 1 are
dead code; simplify the layout by removing the single-agent branches and using
the multi-agent classes directly for the container and the agent card. Update
the outer container JSX (where agents.map is rendered) to always use "grid
grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10" and update the agent card JSX
(the div with key={agent.id} and className logic) to always use the multi-agent
class "relative flex flex-col items-center border border-border rounded-2xl p-8
bg-card shadow-xl" so the unnecessary ternary checks around agents.length are
eliminated.
In `@packages/web/src/app/api/`(server)/webhook/route.ts:
- Around line 246-252: Wrap the call to processGitLabMergeRequest in a try-catch
to mirror the note-event handling: invoke await
processGitLabMergeRequest(gitlabClient, body.project.id, mrPayload,
env.GITLAB_REVIEW_AGENT_HOST) inside try, and on catch log the error with
context (including body.project.id and event type) and return a successful
webhook response so GitLab doesn't retry; ensure you reference
processGitLabMergeRequest, gitlabClient, mrPayload and
env.GITLAB_REVIEW_AGENT_HOST when adding the logging/context.
- Around line 220-226: Wrap the call to processGitLabMergeRequest(gitlabClient,
body.project.id, body, env.GITLAB_REVIEW_AGENT_HOST) in a try-catch inside the
webhook route handler; on error catch the exception, log the full error
(including contextual values like body.project.id and
env.GITLAB_REVIEW_AGENT_HOST) using the existing logger (or console.error if
none), and return a non-retriable HTTP response (e.g., 200/202 with an error
payload) instead of letting the exception bubble up to produce a 500. Ensure the
catch only suppresses delivery retries while still surfacing enough detail in
logs for debugging.
In `@packages/web/src/features/agents/review-agent/app.ts`:
- Around line 62-80: Extract the duplicated log setup in
processGitHubPullRequest and processGitLabMergeRequest into a single helper
(e.g., getReviewAgentLogPath(identifier)) that checks
env.REVIEW_AGENT_LOGGING_ENABLED, ensures the review-agent directory exists
(fs.existsSync + fs.mkdirSync with recursive), builds the timestamp using the
same toLocaleString/replace logic, composes the filename with the provided
identifier (replace uses of mrPayload.object_attributes.iid or pullRequest
number), calls logger.info with the final path, and returns the path or
undefined; then replace the duplicate blocks in both functions with a call to
this helper.
In `@packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts`:
- Around line 13-18: The org lookup inside fetchFileContent (currently using
__unsafePrisma.org.findUnique with SINGLE_TENANT_ORG_ID and throwing if org is
missing) causes repeated DB queries; refactor fetchFileContent to accept an org
(or orgId/needed org fields) as an argument and remove the internal
__unsafePrisma.org.findUnique call so callers resolve org once upstream and pass
it in, or alternatively add a lightweight in-memory cache keyed by
SINGLE_TENANT_ORG_ID and reuse the cached org instead of re-querying each call.
In `@packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts`:
- Around line 35-41: The generateText call in invokeDiffReviewLlm.ts currently
passes the detailed review instructions in the system parameter and a generic
"Review the code changes." as the prompt, which can confuse some providers;
update the call to use a concise role/behavior string for system (e.g., a short
reviewer persona) and pass the detailed review text stored in the prompt
variable as the prompt/user message instead. Modify the generateText invocation
(function generateText, params model, system, prompt, providerOptions,
temperature) so system contains role/behavior guidance and prompt is the
detailed review instructions currently in the prompt variable, keeping
providerOptions and temperature unchanged.
In `@packages/web/src/features/git/getFileSourceApi.ts`:
- Line 10: The import currently brings in Org and PrismaClient as runtime
imports even though they are only used as types; change the import in
getFileSourceApi.ts to a type-only import by replacing "import { Org,
PrismaClient } from '@sourcebot/db';" with "import type { Org, PrismaClient }
from '@sourcebot/db';" and ensure no runtime references to Org or PrismaClient
remain so the type-only import is valid.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a2462b8d-0146-426e-8d4c-f6797bd49a90
📥 CommitsReviewing files that changed from the base of the PR and between 251f5b5 and de3bd15.
⛔ Files ignored due to path filters (1)
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)packages/web/src/features/agents/review-agent/types.ts (1)🤖 Prompt for all review comments with AI agents69-73: ⚠️ Potential issue | 🟡 Minor
Make diff_refs nullable/optional in both GitLab webhook interfaces.
packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts already documents that merge request hooks can omit or null diff_refs on some actions, but these interfaces still require it. That keeps downstream code falsely narrowed and masks the null-handling path the GitLab flow already depends on.
Suggested type fixexport interface GitLabMergeRequestPayload { object_kind: string; object_attributes: { iid: number; title: string; description: string | null; action: string; last_commit: { id: string; }; - diff_refs: { + diff_refs?: { base_sha: string; head_sha: string; start_sha: string; - }; + } | null; }; project: { id: number; name: string; path_with_namespace: string; @@ export interface GitLabNotePayload { object_kind: string; object_attributes: { note: string; noteable_type: string; }; merge_request: { iid: number; title: string; description: string | null; last_commit: { id: string; }; - diff_refs: { + diff_refs?: { base_sha: string; head_sha: string; start_sha: string; - }; + } | null; }; project: { id: number; name: string; path_with_namespace: string;Also applies to: 97-101
🤖 Prompt for AI AgentsVerify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/types.ts` around lines 69 - 73, The diff_refs property in the GitLab webhook interfaces is currently required but can be omitted/null for some MR actions; update both occurrences of diff_refs in this file to be nullable/optional (e.g., change from diff_refs: { base_sha: string; head_sha: string; start_sha: string; } to diff_refs?: { base_sha: string; head_sha: string; start_sha: string; } | null) so downstream code can handle the null/undefined path; ensure you update both interface occurrences referenced in the comment (the MR webhook interface and the other GitLab webhook interface at the second occurrence) and run type checks to confirm no remaining narrow assumptions.
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/web/src/app/api/`(server)/webhook/route.ts:
- Around line 99-117: The GitLab webhook branch uses body typed as unknown and
relies on isGitLabMergeRequestEvent / isGitLabNoteEvent guards but still
dereferences body.project and body.merge_request (e.g., body.project.id,
body.merge_request.iid/title/description/last_commit/diff_refs) without
validating their shapes; add Zod schemas (e.g., GitLabProjectSchema,
GitLabMergeRequestSchema, GitLabNoteSchema or a combined GitLabWebhookSchema)
and in the route handler parse await request.json(), call schema.safeParse(); if
parse fails return requestBodySchemaValidationError, otherwise use the parsed
value for downstream logic instead of assuming fields exist. Ensure you
reference and replace unchecked accesses in the branches that used
isGitLabMergeRequestEvent / isGitLabNoteEvent to use the validated parsed
object.
In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts`:
- Around line 33-34: The repo lookup key is derived incorrectly from
mrPayload.project.name; change the repo variable (repoName) to use the last
segment of mrPayload.project.path_with_namespace instead (e.g., const repoName =
mrPayload.project.path_with_namespace.split('/').pop() or equivalent) so that
the repo used when calling fetchFileContent() matches the stored repo.name;
update any use of namespace/repoName pair (namespace and repoName) accordingly.
---
Duplicate comments:
In `@packages/web/src/features/agents/review-agent/types.ts`:
- Around line 69-73: The diff_refs property in the GitLab webhook interfaces is
currently required but can be omitted/null for some MR actions; update both
occurrences of diff_refs in this file to be nullable/optional (e.g., change from
diff_refs: { base_sha: string; head_sha: string; start_sha: string; } to
diff_refs?: { base_sha: string; head_sha: string; start_sha: string; } | null)
so downstream code can handle the null/undefined path; ensure you update both
interface occurrences referenced in the comment (the MR webhook interface and
the other GitLab webhook interface at the second occurrence) and run type checks
to confirm no remaining narrow assumptions.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2460ae46-0310-47d2-adc3-95f59f241b30
📥 CommitsReviewing files that changed from the base of the PR and between ec2dc25 and 456fa94.
⛔ Files ignored due to path filters (1)
Sorry, something went wrong.
There was a problem hiding this comment.
packages/web/src/app/api/(server)/webhook/route.ts (1)🤖 Prompt for all review comments with AI agentspackages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts (1)249-260: Consider adding explicit type annotation to synthetic MR payload.
The inline mrPayload object is structurally correct, but adding an explicit type annotation would provide compile-time verification that it matches GitLabMergeRequestPayload and improve code clarity.
♻️ Add type annotation🤖 Prompt for AI Agents+ import { GitLabMergeRequestPayload } from "@/features/agents/review-agent/types"; // ... in the handler: - const mrPayload = { + const mrPayload: GitLabMergeRequestPayload = { object_kind: "merge_request", object_attributes: {Verify each finding against the current code and only fix it if needed. In `@packages/web/src/app/api/`(server)/webhook/route.ts around lines 249 - 260, The inline mrPayload object lacks an explicit type annotation; annotate it as GitLabMergeRequestPayload to get compile-time checking and clarity. Update the declaration of mrPayload (the object built from parsed.data.merge_request and parsed.data.project) to include the type GitLabMergeRequestPayload, ensure the fields you set (object_kind, object_attributes, project) conform to that type, and adjust any property names or casts if TypeScript reports mismatches in the function handling the webhook in route.ts.37-49: Minor style note: type assertions before validation.
Lines 38-39 cast to string before the null check on line 41. While functionally safe (falsy check catches undefined), a cleaner pattern would be to access the properties without casting and let the null check handle type narrowing.
♻️ Optional cleaner pattern🤖 Prompt for AI Agentsconst sourcebotFileDiffs: (sourcebot_file_diff | null)[] = fileDiffs.map((fileDiff) => { - const fromPath = fileDiff.old_path as string; - const toPath = fileDiff.new_path as string; + const fromPath = fileDiff.old_path; + const toPath = fileDiff.new_path; if (!fromPath || !toPath) { logger.debug(`Skipping file due to missing old_path (${fromPath}) or new_path (${toPath})`); return null; }Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts` around lines 37 - 49, The current code assigns fromPath and toPath using type assertions before checking for null/undefined; change the pattern in the fileDiffs mapping (the sourcebotFileDiffs creation) to read fileDiff.old_path and fileDiff.new_path without "as string" first, perform the null/undefined/falsy check (if (!fromPath || !toPath) ...) to let TypeScript narrow the types, and only cast or treat them as strings after the check (or simply rely on the narrowed type) so the null check is meaningful and avoids premature assertions in the sourcebotFileDiffs / fileDiffs mapping logic.
Verify each finding against the current code and only fix it if needed. Nitpick comments: In `@packages/web/src/app/api/`(server)/webhook/route.ts: - Around line 249-260: The inline mrPayload object lacks an explicit type annotation; annotate it as GitLabMergeRequestPayload to get compile-time checking and clarity. Update the declaration of mrPayload (the object built from parsed.data.merge_request and parsed.data.project) to include the type GitLabMergeRequestPayload, ensure the fields you set (object_kind, object_attributes, project) conform to that type, and adjust any property names or casts if TypeScript reports mismatches in the function handling the webhook in route.ts. In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts`: - Around line 37-49: The current code assigns fromPath and toPath using type assertions before checking for null/undefined; change the pattern in the fileDiffs mapping (the sourcebotFileDiffs creation) to read fileDiff.old_path and fileDiff.new_path without "as string" first, perform the null/undefined/falsy check (if (!fromPath || !toPath) ...) to let TypeScript narrow the types, and only cast or treat them as strings after the check (or simply rely on the narrowed type) so the null check is meaningful and avoids premature assertions in the sourcebotFileDiffs / fileDiffs mapping logic.
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e1fa14f8-a173-41ae-ac05-734028458bd7
📥 CommitsReviewing files that changed from the base of the PR and between 6c006a0 and cd9fda5.
📒 Files selected for processing (3)
Sorry, something went wrong.
|
@msukkari @brendan-kellam A review on this one would be greatly appreciated, as we're keen to give it a try on a few repos internally :) |
Sorry, something went wrong.
|
✅ Actions performed
Review triggered.
|
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)packages/web/src/features/agents/review-agent/types.ts (1)🤖 Prompt for all review comments with AI agents73-101: Tighten the webhook discriminators.
object_kind and noteable_type are plain z.string(), so unrelated GitLab payloads can still satisfy these schemas if the rest of the shape matches. Using literals here would reject unsupported hooks earlier and make downstream narrowing safer.
🔎 Suggested schema tightening🤖 Prompt for AI Agentsexport const gitLabMergeRequestPayloadSchema = z.object({ - object_kind: z.string(), + object_kind: z.literal("merge_request"), object_attributes: z.object({ iid: z.number(), title: z.string(), description: z.string().nullable(), action: z.string(), last_commit: z.object({ id: z.string() }), diff_refs: gitLabDiffRefsSchema, }), project: gitLabProjectSchema, }); export const gitLabNotePayloadSchema = z.object({ - object_kind: z.string(), + object_kind: z.literal("note"), object_attributes: z.object({ note: z.string(), - noteable_type: z.string(), + noteable_type: z.literal("MergeRequest"), }),Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/types.ts` around lines 73 - 101, The schemas gitLabMergeRequestPayloadSchema and gitLabNotePayloadSchema use broad z.string() for discriminators allowing unrelated webhooks to pass; update the object_kind fields to z.literal('merge_request') in both gitLabMergeRequestPayloadSchema and gitLabNotePayloadSchema, and change noteable_type in gitLabNotePayloadSchema to the appropriate literal (e.g., z.literal('MergeRequest') or the exact GitLab value) so the schemas reject non-merge-request hooks and make downstream type narrowing safe.
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts`:
- Line 100: The head_sha assignment currently uses mr.sha ?? "" which can
discard a valid webhook commit; change the fallback in the head_sha field to
prefer the webhook value by using mr.sha ??
mrPayload.object_attributes.last_commit.id ?? "" (update the head_sha
construction inside gitlabMrParser.ts where head_sha is set) so the MR flow
retains the webhook-provided commit id when MergeRequests.show() lacks sha.
---
Nitpick comments:
In `@packages/web/src/features/agents/review-agent/types.ts`:
- Around line 73-101: The schemas gitLabMergeRequestPayloadSchema and
gitLabNotePayloadSchema use broad z.string() for discriminators allowing
unrelated webhooks to pass; update the object_kind fields to
z.literal('merge_request') in both gitLabMergeRequestPayloadSchema and
gitLabNotePayloadSchema, and change noteable_type in gitLabNotePayloadSchema to
the appropriate literal (e.g., z.literal('MergeRequest') or the exact GitLab
value) so the schemas reject non-merge-request hooks and make downstream type
narrowing safe.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2f200f46-48a5-40e2-8f26-35d18cb99089
📥 CommitsReviewing files that changed from the base of the PR and between 6c006a0 and ca8ace9.
📒 Files selected for processing (4)
Sorry, something went wrong.
|
Prepared a fix for the two open CodeRabbit findings:
Patch is available on my fork branch: aiSynergy37:fix/pr-1104-gitlab-webhook-schemas If helpful, maintainers can cherry-pick directly: |
Sorry, something went wrong.
|
✅ Actions performed
Review triggered.
|
Sorry, something went wrong.
There was a problem hiding this comment.
packages/shared/src/env.server.ts (1)🤖 Prompt for all review comments with AI agentspackages/web/src/features/agents/review-agent/app.ts (1)201-201: Allow host:port in GITLAB_REVIEW_AGENT_HOST validation.
Current validation rejects : so values like gitlab.example.com:8443 fail, even though downstream URL assembly supports them. Consider widening validation to accept optional ports.
Suggested adjustment🤖 Prompt for AI Agents- 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' }), + GITLAB_REVIEW_AGENT_HOST: z.string() + .default('gitlab.com') + .transform(s => s.trim().replace(/^https?:\/\//i, '').replace(/\/+$/, '')) + .refine( + s => /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?::\d{1,5})?$/i.test(s), + { message: 'invalid host[:port]' } + ),Verify each finding against the current code and only fix it if needed. In `@packages/shared/src/env.server.ts` at line 201, The GITLAB_REVIEW_AGENT_HOST zod schema currently rejects host:port because the refine regex disallows ':'; update the validation on GITLAB_REVIEW_AGENT_HOST (the .transform(...) and .refine(...) chain) to allow an optional port by changing the regex to accept an optional colon followed by digits (e.g. adjust the refine pattern from /^[a-z0-9.-]+$/i to something like /^[a-z0-9.-]+(?::\d+)?$/i), keep the existing transform that strips http(s):// and trailing slashes, and keep or update the refine error message to indicate "invalid hostname or port" if you prefer.packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts (1)60-72: Remove the extra project-id source of truth.
mrPayload.project.id is already in scope and gitlabMrParser() uses that value. Keeping a separate projectId parameter makes it possible to parse one project and post comments to another if a caller ever passes mismatched values.
♻️ Suggested simplification🤖 Prompt for AI Agentsexport async function processGitLabMergeRequest( gitlabClient: InstanceType<typeof Gitlab>, - projectId: number, mrPayload: GitLabMergeRequestPayload, hostDomain: string, ) { @@ - await gitlabPushMrReviews(gitlabClient, projectId, prPayload, fileDiffReviews); + await gitlabPushMrReviews(gitlabClient, mrPayload.project.id, prPayload, fileDiffReviews); }Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/app.ts` around lines 60 - 72, The function processGitLabMergeRequest currently accepts a separate projectId parameter which duplicates mrPayload.project.id and risks mismatched usage; remove the projectId parameter from processGitLabMergeRequest's signature and update the body to derive the project id from mrPayload.project.id (e.g., use mrPayload.project.id when calling gitlabPushMrReviews), then update all call sites to stop passing projectId so the single source of truth is mrPayload; also ensure gitlabMrParser and any other usages still receive the correct values.57-251: Add regression coverage for the new fallback branches in gitlabMrParser().
The suite never exercises mr.sha ?? last_commit.id or mr.diff_refs == null, so the exact GitLab edge cases this PR hardened can regress unnoticed.
🧪 Suggested tests🤖 Prompt for AI Agents+ test('falls back to webhook last_commit.id when show() omits sha', async () => { + const client = makeMockGitlabClient([], { sha: undefined }); + const result = await gitlabMrParser(client, MOCK_MR_PAYLOAD, 'gitlab.com'); + expect(result.head_sha).toBe('abc123def456'); + }); + + test('omits diff_refs when show() returns null diff_refs', async () => { + const client = makeMockGitlabClient([], { diff_refs: null }); + const result = await gitlabMrParser(client, MOCK_MR_PAYLOAD, 'gitlab.com'); + expect(result.diff_refs).toBeUndefined(); + });Verify each finding against the current code and only fix it if needed. In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts` around lines 57 - 251, The tests need to cover the new fallback branches in gitlabMrParser: add unit cases that (1) pass an MR payload where mr.sha is null and last_commit.id is present and assert the resulting head_sha equals last_commit.id, and (2) pass an MR payload where mr.diff_refs is null (or missing) and assert diff_refs on the result are derived via the parser's fallback logic; locate the test cases in the gitlabMrParser.test.ts suite and use the existing makeMockGitlabClient / MOCK_MR_PAYLOAD patterns, invoking gitlabMrParser(client, payload, host) and asserting on result.head_sha and result.diff_refs to ensure the fallbacks (mr.sha ?? last_commit.id and handling of mr.diff_refs == null) are exercised.
Verify each finding against the current code and only fix it if needed. Nitpick comments: In `@packages/shared/src/env.server.ts`: - Line 201: The GITLAB_REVIEW_AGENT_HOST zod schema currently rejects host:port because the refine regex disallows ':'; update the validation on GITLAB_REVIEW_AGENT_HOST (the .transform(...) and .refine(...) chain) to allow an optional port by changing the regex to accept an optional colon followed by digits (e.g. adjust the refine pattern from /^[a-z0-9.-]+$/i to something like /^[a-z0-9.-]+(?::\d+)?$/i), keep the existing transform that strips http(s):// and trailing slashes, and keep or update the refine error message to indicate "invalid hostname or port" if you prefer. In `@packages/web/src/features/agents/review-agent/app.ts`: - Around line 60-72: The function processGitLabMergeRequest currently accepts a separate projectId parameter which duplicates mrPayload.project.id and risks mismatched usage; remove the projectId parameter from processGitLabMergeRequest's signature and update the body to derive the project id from mrPayload.project.id (e.g., use mrPayload.project.id when calling gitlabPushMrReviews), then update all call sites to stop passing projectId so the single source of truth is mrPayload; also ensure gitlabMrParser and any other usages still receive the correct values. In `@packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts`: - Around line 57-251: The tests need to cover the new fallback branches in gitlabMrParser: add unit cases that (1) pass an MR payload where mr.sha is null and last_commit.id is present and assert the resulting head_sha equals last_commit.id, and (2) pass an MR payload where mr.diff_refs is null (or missing) and assert diff_refs on the result are derived via the parser's fallback logic; locate the test cases in the gitlabMrParser.test.ts suite and use the existing makeMockGitlabClient / MOCK_MR_PAYLOAD patterns, invoking gitlabMrParser(client, payload, host) and asserting on result.head_sha and result.diff_refs to ensure the fallbacks (mr.sha ?? last_commit.id and handling of mr.diff_refs == null) are exercised.
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c140fde0-e600-49bc-ad81-f06bab25ab74
📥 CommitsReviewing files that changed from the base of the PR and between ca8ace9 and a824d7a.
⛔ Files ignored due to path filters (1)
Sorry, something went wrong.
|
@msukkari / @brendan-kellam I've rebased this branch based on the changes in !1134. Let me know if needs anything additional, or if we could get this merged and released as an experimental feature? 👍 |
Sorry, something went wrong.
Adds support for the AI Review Agent to review GitLab Merge Requests, mirroring the existing GitHub PR review functionality. Also fixes several bugs discovered during implementation and improves the shared review pipeline.
---
## New files
### `packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts`
Parses a GitLab MR webhook payload into the shared `sourcebot_pr_payload` format. Calls `MergeRequests.show()` and `MergeRequests.allDiffs()` in parallel — the API response is used for `title`, `description`, `sha`, and `diff_refs` (which can be absent in webhook payloads for `update` action events), while per-file diffs are parsed using the existing `parse-diff` library.
### `packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.ts`
Posts review comments back to GitLab using `MergeRequestDiscussions.create()` with a position object carrying `base_sha`, `head_sha`, and `start_sha`. Falls back to `MergeRequestNotes.create()` (a general MR note) if the inline comment is rejected by the API (e.g. the line is not within the diff), ensuring reviews are always surfaced even when precise positioning fails.
### Test files (4 new files, 34 tests total)
- `githubPrParser.test.ts` — diff parsing and metadata mapping for the GitHub parser
- `githubPushPrReviews.test.ts` — single-line vs multi-line comment parameters, error resilience
- `gitlabMrParser.test.ts` — API call arguments, metadata mapping, diff parsing, edge cases (empty diffs, nested groups, null description, API failures)
- `gitlabPushMrReviews.test.ts` — inline comment posting, fallback behaviour, missing `diff_refs` guard, multi-file iteration
---
## Modified files
### `packages/web/src/features/agents/review-agent/types.ts`
- Added `sourcebot_diff_refs` schema/type (`base_sha`, `head_sha`, `start_sha`) and an optional `diff_refs` field on `sourcebot_pr_payload`
- Added `GitLabMergeRequestPayload` and `GitLabNotePayload` interfaces for webhook event typing
### `packages/web/src/features/agents/review-agent/app.ts`
- Added `processGitLabMergeRequest()` function mirroring `processGitHubPullRequest()`: sets up logging, runs the GitLab parser, generates reviews via the shared LLM pipeline, and pushes results
- Removed stale `OPENAI_API_KEY` guards (model availability is now enforced inside `invokeDiffReviewLlm`)
### `packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts`
**Replaces the hardcoded OpenAI client** with the Vercel AI SDK's `generateText` and the shared `getAISDKLanguageModelAndOptions` / `getConfiguredLanguageModels` utilities from `chat/utils.server.ts`. The review agent now uses whichever language model is configured in `config.json`, supporting all providers (Anthropic, Bedrock, Azure, etc.).
- `REVIEW_AGENT_MODEL` env var (matched against `displayName`) selects a specific model when multiple are configured; falls back to `models[0]` with a warning if the name is not found
- Prompt is passed via the `system` parameter with a `"Review the code changes."` user turn, satisfying providers (e.g. Bedrock/Anthropic) that require conversations to begin with a user message
### `packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts`
**Fixes "Not authenticated" error** when the review agent calls `getFileSource`. The original implementation used `withOptionalAuth`, which reads a session cookie — absent in webhook handlers. Now calls `getFileSourceForRepo` directly with `__unsafePrisma` and the single-tenant org, bypassing the session-based auth layer. The webhook handler has already authenticated the request via its own mechanism (GitHub App signature / GitLab token).
### `packages/web/src/features/git/getFileSourceApi.ts`
- Extracted the core repo-lookup + git + language-detection logic into a new exported `getFileSourceForRepo({ path, repo, ref }, { org, prisma })` function
- `getFileSource` now handles auth and audit logging then delegates to `getFileSourceForRepo` — all existing callers are unchanged
### `packages/web/src/app/api/(server)/webhook/route.ts`
- Added GitLab webhook handling alongside the existing GitHub branch
- Verifies `x-gitlab-token` against `GITLAB_REVIEW_AGENT_WEBHOOK_SECRET`
- Handles `Merge Request Hook` events (auto-review on `open`, `update`, `reopen`) and `Note Hook` events (manual `/review` command on MR comments)
- Initialises a `Gitlab` client at module load if `GITLAB_REVIEW_AGENT_TOKEN` is set
### `packages/web/src/app/(app)/agents/page.tsx`
- Split the single "Review Agent" card into two separate cards: **GitHub Review Agent** and **GitLab Review Agent**, each showing its own configuration status
- Removed `OPENAI_API_KEY` from the GitHub card's required env vars (no longer applicable)
### `packages/web/src/app/(app)/components/navigationMenu/navigationItems.tsx` & `index.tsx`
- Added an **Agents** nav item (with `BotIcon`) between Repositories and Settings
- Visible when the user is authenticated **and** at least one agent is configured (GitHub App triple or GitLab token pair), computed in the server component and passed down as `isAgentsVisible`
### `packages/shared/src/env.server.ts`
Added four new environment variables:
| Variable | Purpose |
|---|---|
| `GITLAB_REVIEW_AGENT_WEBHOOK_SECRET` | Verifies the `x-gitlab-token` header on incoming webhooks |
| `GITLAB_REVIEW_AGENT_TOKEN` | Personal or project access token used for GitLab API calls |
| `GITLAB_REVIEW_AGENT_HOST` | GitLab hostname (defaults to `gitlab.com`; set for self-hosted instances) |
| `REVIEW_AGENT_MODEL` | `displayName` of the configured language model to use for reviews; falls back to the first model if unset or not matched |
### `packages/web/package.json`
Added `@gitbeaker/rest` dependency (already used in `packages/backend`).
---
## Bug fixes
| Bug | Fix |
|---|---|
| `"Not authenticated"` when fetching file content from the review agent | `fetchFileContent` now calls `getFileSourceForRepo` directly instead of `getFileSource` (which gates on session auth) |
| `"diff_refs is missing"` when posting GitLab MR reviews | `gitlabMrParser` now fetches the full MR via `MergeRequests.show()` instead of relying on the webhook payload, which omits `diff_refs` on `update` events |
| Bedrock/Anthropic rejection: `"A conversation must start with a user message"` | `invokeDiffReviewLlm` now passes the prompt via `system` + a `prompt` user turn instead of a `system`-role entry inside `messages` |
| Review agent silently used `models[0]` with no way to specify a different model | New `REVIEW_AGENT_MODEL` env var selects by `displayName` |
There was a problem hiding this comment.
LGTM thanks!
Sorry, something went wrong.
|
release build is running atm, will merge afterwards |
Sorry, something went wrong.
|
Wow, thanks folks, I'll definitely give this a try in our projects as well! 👏👏 |
Sorry, something went wrong.
@gaeljw I've just opened #1143 which takes things one step further to support "dynamic" agents :) I think I've covered most of the bases, but feel free to take a look and suggest any additions... |
Sorry, something went wrong.
) * fix(web): restore ServiceError boundary in `getFileSourceForRepo` ## Problem In v4.16.14 (PR #1104, GitLab MR Review Agent), the core file-fetch logic was extracted from inside `sew()` into a standalone `getFileSourceForRepo` function so it could be called by privileged server-side callers (e.g. the review agent webhook handler) without going through the auth middleware. The extraction introduced a missing error boundary. The catch block inside `getFileSourceForRepo` handled two known git error patterns and **re-threw everything else**: ```ts // getFileSourceApi.ts — before this fix } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); if (errorMessage.includes('does not exist') || ...) return fileNotFound(...); if (errorMessage.includes('unknown revision') || ...) return unexpectedError(...); throw error; // ← propagates uncaught; sew() no longer wraps this code path } ``` Because `getFileSourceForRepo` is no longer inside `sew()`, any re-thrown exception escapes as a fatal error through the Next.js server task runner, producing the `z.onFatalException` / `z.attemptTask` stack trace seen in production on v4.16.14. A second contributing factor: the review agent was also changed in v4.16.14 to pass `ref: pr_payload.head_sha` where `ref` was previously `undefined`. If the bare clone hasn't fetched that commit yet, `git show` throws with `"unknown revision"` — which fell into the same unhandled re-throw path. Rolling back to v4.16.13 restored the original `sew()`-wrapped code path, which is why the rollback fixed the issue. ## Fix Two targeted changes in `getFileSourceApi.ts`: 1. **`throw error` → `return unexpectedError(errorMessage)`** — ensures `getFileSourceForRepo` always returns `FileSourceResponse | ServiceError` and never rejects its promise. This is the root-cause fix. 2. **`unexpectedError(...)` → `invalidGitRef(gitRef)`** for the `"unknown revision"` / `"bad revision"` / `"invalid object name"` branch — uses the semantically correct error type (already imported), which also gives callers a more actionable error when `head_sha` hasn't been fetched. ## Tests Added `getFileSourceApi.test.ts` with 19 tests covering: - **Repository validation** — `NOT_FOUND` when repo is absent from the DB; correct `findFirst` query shape. - **Input validation** — path traversal and null-byte paths → `FILE_NOT_FOUND`; refs starting with `-` → `INVALID_GIT_REF` (flag-injection guard). - **Git error handling** (the regression suite): - `"does not exist"` / `"fatal: path"` → `FILE_NOT_FOUND` - `"unknown revision"` (unfetched `head_sha`) → `INVALID_GIT_REF` - `"bad revision"` / `"invalid object name"` → `INVALID_GIT_REF` - **Unrecognised error → `UNEXPECTED_ERROR`, not a throw** — explicit regression test; before the fix, `.resolves` would fail because the promise rejected. - **Successful response** — source content, language, ref fallback chain (`ref` → `defaultBranch` → `HEAD`), correct `cwd` path. - **Language detection** — prefers `.gitattributes`; falls back to filename-based detection when the file is absent. ## Files changed | File | Change | |------|--------| | `packages/web/src/features/git/getFileSourceApi.ts` | `throw error` → `return unexpectedError(errorMessage)`; invalid-ref branch now returns `invalidGitRef(gitRef)` | | `packages/web/src/features/git/getFileSourceApi.test.ts` | New — 19 tests | * fix(web): harden getFileSourceForRepo error boundary Three fixes to getFileSourceForRepo, which was extracted outside sew() in v4.16.14 and lost its error boundary: - Wrap the entire function body in a top-level try/catch so exceptions from prisma, getRepoPath, simpleGit().cwd(), language helpers, and URL builders are converted to unexpectedError rather than propagating as fatal Next.js task-runner exceptions. - Add unresolvedGitRef() to serviceError.ts (errorCode: INVALID_GIT_REF, distinct message) and use it for "unknown revision"/"bad revision"/ "invalid object name" git errors, replacing the syntactic invalidGitRef message that was misleading for unfetched head_sha refs. - Fix the simple-git vi.mock() factory in the test file to map both the default and named exports to the same hoisted mock fn, ensuring the SUT and the test body reference identical mocks. Add a test for the outer catch (DB throws) and tighten INVALID_GIT_REF assertions to distinguish syntactic from unresolved-ref errors by message content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add CHANGELOG entry * refactor(web): use sew() instead of bare try/catch in getFileSourceForRepo The top-level try/catch added to getFileSourceForRepo silently swallowed unexpected errors with no Sentry capture or log entry. Replace it with sew(), which provides the same ServiceError conversion plus Sentry reporting and structured logging. The inner git-specific catch is preserved unchanged — sew() only handles anything that escapes it (DB errors, getRepoPath, URL builders, etc.). Update the sew mock in the test file to catch and convert exceptions, matching the real sew() behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Gavin Williams <gavin.williams@getchip.uk> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
| Back | FazBrowse Home | New Git URL |
Adds support for the AI Review Agent to review GitLab Merge Requests, mirroring the existing GitHub PR review functionality. Also fixes several bugs discovered during implementation and improves the shared review pipeline.
New files
packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.ts
Parses a GitLab MR webhook payload into the shared sourcebot_pr_payload format. Calls MergeRequests.show() and MergeRequests.allDiffs() in parallel — the API response is used for title, description, sha, and diff_refs (which can be absent in webhook payloads for update action events), while per-file diffs are parsed using the existing parse-diff library.
packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.ts
Posts review comments back to GitLab using MergeRequestDiscussions.create() with a position object carrying base_sha, head_sha, and start_sha. Falls back to MergeRequestNotes.create() (a general MR note) if the inline comment is rejected by the API (e.g. the line is not within the diff), ensuring reviews are always surfaced even when precise positioning fails.
Test files (4 new files, 34 tests total)
Modified files
packages/web/src/features/agents/review-agent/types.ts
packages/web/src/features/agents/review-agent/app.ts
packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts
Replaces the hardcoded OpenAI client with the Vercel AI SDK's generateText and the shared getAISDKLanguageModelAndOptions / getConfiguredLanguageModels utilities from chat/utils.server.ts. The review agent now uses whichever language model is configured in config.json, supporting all providers (Anthropic, Bedrock, Azure, etc.).
packages/web/src/features/agents/review-agent/nodes/fetchFileContent.ts
Fixes "Not authenticated" error when the review agent calls getFileSource. The original implementation used withOptionalAuth, which reads a session cookie — absent in webhook handlers. Now calls getFileSourceForRepo directly with __unsafePrisma and the single-tenant org, bypassing the session-based auth layer. The webhook handler has already authenticated the request via its own mechanism (GitHub App signature / GitLab token).
packages/web/src/features/git/getFileSourceApi.ts
packages/web/src/app/api/(server)/webhook/route.ts
packages/web/src/app/(app)/agents/page.tsx
packages/web/src/app/(app)/components/navigationMenu/navigationItems.tsx & index.tsx
packages/shared/src/env.server.ts
Added four new environment variables:
packages/web/package.json
Added @gitbeaker/rest dependency (already used in packages/backend).
Bug fixes
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation
Chores