@krotovm/gitlab-ai-review 1.0.22 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/ci-review.js +3 -3
- package/dist/prompt/index.js +24 -86
- package/dist/prompt/messages.js +2 -130
- package/dist/prompt/templates/postprocess-system.js +36 -0
- package/dist/prompt/templates/review-system.js +47 -0
- package/dist/prompt/templates/triage-system.js +17 -0
- package/dist/prompt/templates/user-prompts.js +72 -0
- package/package.json +1 -1
package/dist/cli/ci-review.js
CHANGED
|
@@ -382,7 +382,7 @@ export async function reviewMergeRequestMultiPass(params) {
|
|
|
382
382
|
const skippedCount = changes.length - reviewFiles.length;
|
|
383
383
|
logStep(`Triage: ${reviewFiles.length} file(s) to review, ${skippedCount} skipped. Summary: ${triageResult.summary.slice(0, 120)}...`);
|
|
384
384
|
if (reviewFiles.length === 0) {
|
|
385
|
-
const DISCLAIMER = "This comment was generated by
|
|
385
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
386
386
|
return `No confirmed bugs or high-value optimizations found.\n\n---\n_${DISCLAIMER}_`;
|
|
387
387
|
}
|
|
388
388
|
logStep(`Pass 2/4: reviewing ${reviewFiles.length} file(s) (concurrency=${reviewConcurrency})`);
|
|
@@ -412,7 +412,7 @@ export async function reviewMergeRequestMultiPass(params) {
|
|
|
412
412
|
maxFindings,
|
|
413
413
|
});
|
|
414
414
|
if (consolidateMessages == null) {
|
|
415
|
-
const DISCLAIMER = "This comment was generated by
|
|
415
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
416
416
|
return `No confirmed bugs or high-value optimizations found.\n\n---\n_${DISCLAIMER}_`;
|
|
417
417
|
}
|
|
418
418
|
try {
|
|
@@ -449,7 +449,7 @@ export async function reviewMergeRequestMultiPass(params) {
|
|
|
449
449
|
}
|
|
450
450
|
catch (error) {
|
|
451
451
|
logStep(`Consolidation failed: ${error?.message ?? error}. Returning raw per-file findings.`);
|
|
452
|
-
const DISCLAIMER = "This comment was generated by
|
|
452
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
453
453
|
const raw = perFileFindings
|
|
454
454
|
.filter((f) => !f.findings.includes("No issues found.") &&
|
|
455
455
|
!f.findings.includes("No confirmed bugs"))
|
package/dist/prompt/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** @format */
|
|
2
2
|
import { buildMainSystemMessages, FILE_REVIEW_SYSTEM, TRIAGE_SYSTEM, } from "./messages.js";
|
|
3
3
|
import { normalizeReviewFindingsMarkdown, sanitizeGitLabMarkdown, truncateWithMarker, } from "./utils.js";
|
|
4
|
+
import { buildConsolidateSystemLines, buildVerificationSystemLines, } from "./templates/postprocess-system.js";
|
|
5
|
+
import { buildConsolidateUserContent, buildFileReviewUserContent, buildMainReviewUserContent, buildTriageUserContent, buildVerificationUserContent, } from "./templates/user-prompts.js";
|
|
4
6
|
export const DEFAULT_PROMPT_LIMITS = {
|
|
5
7
|
maxDiffs: 50,
|
|
6
8
|
maxDiffChars: 16000,
|
|
@@ -33,15 +35,11 @@ export const buildPrompt = ({ changes, limits, allowTools = false, }) => {
|
|
|
33
35
|
const toolNote = allowTools
|
|
34
36
|
? "Tools (get_file_at_ref, grep_repository) are available — use them to verify suspicions and inspect truncated or omitted files."
|
|
35
37
|
: "Tools are unavailable in this run; rely only on visible diff evidence.";
|
|
36
|
-
const userContent =
|
|
37
|
-
|
|
38
|
+
const userContent = buildMainReviewUserContent({
|
|
39
|
+
stats,
|
|
38
40
|
toolNote,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
changesText || "(no changes provided)",
|
|
42
|
-
"",
|
|
43
|
-
"Produce your review now. Follow the system instructions strictly.",
|
|
44
|
-
].join("\n");
|
|
41
|
+
changesText,
|
|
42
|
+
});
|
|
45
43
|
const boundedContent = truncateWithMarker(userContent, effectiveLimits.maxTotalPromptChars, "prompt payload");
|
|
46
44
|
return [...MESSAGES, { role: "user", content: boundedContent }];
|
|
47
45
|
};
|
|
@@ -50,26 +48,12 @@ export const buildPrompt = ({ changes, limits, allowTools = false, }) => {
|
|
|
50
48
|
// ---------------------------------------------------------------------------
|
|
51
49
|
export const DEFAULT_MAX_FINDINGS = 5;
|
|
52
50
|
export const DEFAULT_REVIEW_CONCURRENCY = 5;
|
|
53
|
-
export const DIFF_SNIPPET_CHARS = 300;
|
|
54
51
|
export function buildTriagePrompt(changes) {
|
|
55
|
-
const fileEntries = changes.map((c) => {
|
|
56
|
-
const flags = [];
|
|
57
|
-
if (c.new_file)
|
|
58
|
-
flags.push("new");
|
|
59
|
-
if (c.deleted_file)
|
|
60
|
-
flags.push("deleted");
|
|
61
|
-
if (c.renamed_file)
|
|
62
|
-
flags.push("renamed");
|
|
63
|
-
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
64
|
-
const snippet = c.diff.slice(0, DIFF_SNIPPET_CHARS);
|
|
65
|
-
const truncNote = c.diff.length > DIFF_SNIPPET_CHARS ? "..." : "";
|
|
66
|
-
return `### ${c.path}${flagStr}\n\`\`\`\n${snippet}${truncNote}\n\`\`\``;
|
|
67
|
-
});
|
|
68
52
|
return [
|
|
69
53
|
TRIAGE_SYSTEM,
|
|
70
54
|
{
|
|
71
55
|
role: "user",
|
|
72
|
-
content:
|
|
56
|
+
content: buildTriageUserContent(changes),
|
|
73
57
|
},
|
|
74
58
|
];
|
|
75
59
|
}
|
|
@@ -103,25 +87,17 @@ export function buildFileReviewPrompt(params) {
|
|
|
103
87
|
const toolNote = allowTools
|
|
104
88
|
? "Tools (get_file_at_ref, grep_repository) are available to verify suspicions or read the full file."
|
|
105
89
|
: "Tools are unavailable; rely only on visible diff evidence.";
|
|
106
|
-
const otherFilesNote = otherChangedFiles.length > 0
|
|
107
|
-
? `\nOther files changed in this MR: ${otherChangedFiles.join(", ")}`
|
|
108
|
-
: "";
|
|
109
90
|
return [
|
|
110
91
|
FILE_REVIEW_SYSTEM,
|
|
111
92
|
{
|
|
112
93
|
role: "user",
|
|
113
|
-
content:
|
|
114
|
-
|
|
115
|
-
otherFilesNote,
|
|
116
|
-
"",
|
|
117
|
-
toolNote,
|
|
118
|
-
"",
|
|
119
|
-
`File: ${filePath}`,
|
|
120
|
-
"Diff:",
|
|
94
|
+
content: buildFileReviewUserContent({
|
|
95
|
+
filePath,
|
|
121
96
|
fileDiff,
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
97
|
+
summary,
|
|
98
|
+
otherChangedFiles,
|
|
99
|
+
toolNote,
|
|
100
|
+
}),
|
|
125
101
|
},
|
|
126
102
|
];
|
|
127
103
|
}
|
|
@@ -137,32 +113,15 @@ export function buildConsolidatePrompt(params) {
|
|
|
137
113
|
return [
|
|
138
114
|
{
|
|
139
115
|
role: "system",
|
|
140
|
-
content:
|
|
141
|
-
"You consolidate per-file code review findings into a final ranked list.",
|
|
142
|
-
`Select the top ${maxFindings} most important findings. Deduplicate overlapping issues.`,
|
|
143
|
-
"Preserve this exact per-finding markdown block:",
|
|
144
|
-
"`- [high|medium] <title>`",
|
|
145
|
-
"` File: <path>`",
|
|
146
|
-
"` Line: ~<N>`",
|
|
147
|
-
"` Why: <one concise sentence with key evidence>`",
|
|
148
|
-
"Rank by: (1) [high] before [medium], (2) correctness > security > perf.",
|
|
149
|
-
"Do not add new findings. Do not add headings, summaries, or commentary.",
|
|
150
|
-
"Drop any finding that: claims a syntax error without quoting the invalid token, claims a function/variable is missing without concrete proof, or flags a refactoring rename as a bug.",
|
|
151
|
-
`If fewer than ${maxFindings} findings exist, return all of them.`,
|
|
152
|
-
'If all findings are low quality or dubious after dedup, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
153
|
-
"GitLab-flavoured markdown.",
|
|
154
|
-
].join("\n"),
|
|
116
|
+
content: buildConsolidateSystemLines(maxFindings).join("\n"),
|
|
155
117
|
},
|
|
156
118
|
{
|
|
157
119
|
role: "user",
|
|
158
|
-
content:
|
|
159
|
-
|
|
160
|
-
"",
|
|
161
|
-
"Per-file findings:",
|
|
120
|
+
content: buildConsolidateUserContent({
|
|
121
|
+
summary,
|
|
162
122
|
findingsText,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
].join("\n"),
|
|
123
|
+
maxFindings,
|
|
124
|
+
}),
|
|
166
125
|
},
|
|
167
126
|
];
|
|
168
127
|
}
|
|
@@ -174,36 +133,15 @@ export function buildVerificationPrompt(params) {
|
|
|
174
133
|
return [
|
|
175
134
|
{
|
|
176
135
|
role: "system",
|
|
177
|
-
content:
|
|
178
|
-
"You are a skeptical verifier of a merge request review.",
|
|
179
|
-
"Your job is to remove weak, speculative, or unsupported findings from the draft list.",
|
|
180
|
-
"Do not add new findings. Keep, rewrite for clarity, or remove existing findings only.",
|
|
181
|
-
"A finding can stay only if it is directly supported by evidence from the per-file findings.",
|
|
182
|
-
"If confidence is not high, drop the finding.",
|
|
183
|
-
"Preserve this exact per-finding markdown block:",
|
|
184
|
-
"`- [high|medium] <title>`",
|
|
185
|
-
"` File: <path>`",
|
|
186
|
-
"` Line: ~<N>`",
|
|
187
|
-
"` Why: <one concise sentence with key evidence>`",
|
|
188
|
-
"Do not add headings, summaries, or extra commentary.",
|
|
189
|
-
`Return at most ${maxFindings} findings.`,
|
|
190
|
-
'If no findings survive verification, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
191
|
-
"GitLab-flavoured markdown.",
|
|
192
|
-
].join("\n"),
|
|
136
|
+
content: buildVerificationSystemLines(maxFindings).join("\n"),
|
|
193
137
|
},
|
|
194
138
|
{
|
|
195
139
|
role: "user",
|
|
196
|
-
content:
|
|
197
|
-
|
|
198
|
-
"",
|
|
199
|
-
"Per-file findings (evidence pool):",
|
|
140
|
+
content: buildVerificationUserContent({
|
|
141
|
+
summary,
|
|
200
142
|
findingsText,
|
|
201
|
-
"",
|
|
202
|
-
"Draft consolidated findings to verify:",
|
|
203
143
|
consolidatedFindings,
|
|
204
|
-
|
|
205
|
-
"Return only the verified final findings.",
|
|
206
|
-
].join("\n"),
|
|
144
|
+
}),
|
|
207
145
|
},
|
|
208
146
|
];
|
|
209
147
|
}
|
|
@@ -232,8 +170,8 @@ export function extractCompletionText(completion) {
|
|
|
232
170
|
}
|
|
233
171
|
return null;
|
|
234
172
|
}
|
|
235
|
-
const ERROR_ANSWER = "
|
|
236
|
-
const DISCLAIMER = "This comment was generated by
|
|
173
|
+
const ERROR_ANSWER = "AI review could not be completed. Please ask a human to review this code change.";
|
|
174
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
237
175
|
export const buildAnswer = (completion) => {
|
|
238
176
|
if (completion instanceof Error) {
|
|
239
177
|
const maybeCause = completion.cause;
|
package/dist/prompt/messages.js
CHANGED
|
@@ -1,134 +1,6 @@
|
|
|
1
1
|
/** @format */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"Return at most 3 findings. Prefer no finding over a weakly supported one.",
|
|
5
|
-
"",
|
|
6
|
-
"WORKFLOW:",
|
|
7
|
-
"1. Parse diff: identify all changed files and note any truncation markers (`[... diff #N truncated ...]` or `[... prompt payload truncated ...]`).",
|
|
8
|
-
"2. Triage files: skim every `diff --git` header to classify each file — files that modify logic or functionality need analysis; files with only cosmetic changes (formatting, renaming for clarity, comments) can be skipped. Prioritize files that alter exported function/method signatures, shared data structures, auth, data access, or concurrency.",
|
|
9
|
-
"3. Analyze: for each triaged file, inspect `+` (added) and changed lines for wrong conditions, missing await, off-by-one, type mismatches, cross-file inconsistencies (renamed symbols with stale callers, changed exported signatures with mismatched callers, updated interfaces with mismatched implementations), security gaps, and clear perf regressions.",
|
|
10
|
-
"4. Tool-assisted verification (when tools are available): use get_file_at_ref to read full files (especially truncated ones) and grep_repository to confirm symbol usage or find callers. Do not guess when you can verify.",
|
|
11
|
-
"5. Report only issues that are tool-confirmed or visually obvious from the diff.",
|
|
12
|
-
"",
|
|
13
|
-
"SCOPE:",
|
|
14
|
-
"- Only flag issues introduced by this diff.",
|
|
15
|
-
"- Focus on added/changed lines (`+`). Context lines (` `) and removed lines (`-`) are reference only.",
|
|
16
|
-
"- Do not comment on untouched code unless required for a proven bug path.",
|
|
17
|
-
"- If you cannot point to a concrete problematic added/changed line and explain in one sentence why it is definitely wrong, skip the finding.",
|
|
18
|
-
"",
|
|
19
|
-
"ACCURACY:",
|
|
20
|
-
"- Only report issues directly supported by diff lines and/or visible imports/exports.",
|
|
21
|
-
"- Do not invent behavior, fields, or code paths not visible in evidence.",
|
|
22
|
-
"- Removed (`-`) lines are historical; do not claim current usage based solely on them.",
|
|
23
|
-
"- If a concept is consistently renamed across files (e.g. `*Type` -> `*Percent`), do not flag missing old-name checks without explicit conflicting evidence in current (`+`) lines.",
|
|
24
|
-
"- Do not report `missing dependency` when the dependency is removed from both usage and declarations in these diffs.",
|
|
25
|
-
"- Truncated diffs may hide context. State uncertainty rather than assuming correctness or incorrectness. If tools are available, fetch the full file before reporting.",
|
|
26
|
-
"- If any part of the execution path depends on code you cannot see in the diff (truncated sections, omitted files, missing context), treat it as uncertainty and do not report a finding.",
|
|
27
|
-
"- If truncation markers indicate omitted context, assume missing context might make the change correct.",
|
|
28
|
-
"",
|
|
29
|
-
"ANTI-HALLUCINATION (mandatory — violations make the review harmful):",
|
|
30
|
-
"- SYNTAX ERRORS: Do not claim syntax errors unless you can quote the exact invalid token from the diff. Count parentheses/brackets on the actual line before reporting.",
|
|
31
|
-
"- MISSING EXPORTS/FUNCTIONS: Do not report missing functions/variables/types/exports unless there is direct usage in added lines and you can see full relevant context. If the diff is truncated or incomplete, you CANNOT claim missing.",
|
|
32
|
-
"- UNDEFINED VARIABLES: Do not claim a variable is undefined unless you verified it is absent in visible added/context lines of the same scope.",
|
|
33
|
-
"- SIGNATURE CHANGES: A function signature change is NOT a bug by itself. Only flag it if you can point to a specific caller in the diff that passes wrong arguments or uses a stale return value.",
|
|
34
|
-
"- REFACTORING: When a diff consistently renames/replaces a concept (e.g. type→percent, contributionType→contributionPercent), this is intentional refactoring. Do not flag the removal of old code or the new pattern as a bug without contradictory evidence.",
|
|
35
|
-
"- If you are not sure that something is a real bug introduced by added/changed lines, do not report it.",
|
|
36
|
-
'- When in doubt between "some issue" and "No confirmed bugs or high-value optimizations found.", choose the no-issues output.',
|
|
37
|
-
"",
|
|
38
|
-
"SELF-CHECK (before outputting any finding):",
|
|
39
|
-
"- Re-read the specific diff lines you cite. Is the evidence actually there?",
|
|
40
|
-
"- Could this be intentional or context-dependent? If yes, skip it.",
|
|
41
|
-
"",
|
|
42
|
-
"PRIORITY: (1) correctness (typo, wrong var, missing await, off-by-one), (2) security (secrets, unsafe eval, unvalidated input), (3) perf regressions (N+1 queries, unbounded loops, missing pagination).",
|
|
43
|
-
"",
|
|
44
|
-
"SEVERITY:",
|
|
45
|
-
"- [high] = deterministic runtime or security issue with a concrete execution path visible in the diff. You must be able to describe exactly what breaks and why.",
|
|
46
|
-
"- [medium] = well-supported but probabilistic issue.",
|
|
47
|
-
"",
|
|
48
|
-
"QUICK CHECKS (always perform):",
|
|
49
|
-
"- Compare added function/method calls against imports/exports for spelling mismatches.",
|
|
50
|
-
"- Flag identifier typos only when there is a clearly similar identifier in the same hunk/file.",
|
|
51
|
-
"- Do not infer typos from names not present in visible evidence.",
|
|
52
|
-
"- Pay special attention to alterations in signatures of exported functions, shared types/interfaces, and global data structures — these have the highest cross-file breakage potential.",
|
|
53
|
-
"- On multi-file diffs: verify cross-file consistency — if a signature, interface, type, or enum changes in one file, check that callers/implementers in other changed files still match.",
|
|
54
|
-
"",
|
|
55
|
-
"OUTPUT FORMAT:",
|
|
56
|
-
"- Each finding must use this 4-line markdown block:",
|
|
57
|
-
"- `- [high|medium] <title>`",
|
|
58
|
-
"- ` File: <path>`",
|
|
59
|
-
"- ` Line: ~<N>`",
|
|
60
|
-
"- ` Why: <one concise sentence with key evidence>`",
|
|
61
|
-
"- No headings, no praise, no code blocks. Do not summarize or explain what changed — only report confirmed issues.",
|
|
62
|
-
'- If no confirmed issues: exactly "No confirmed bugs or high-value optimizations found."',
|
|
63
|
-
"- GitLab-flavoured markdown.",
|
|
64
|
-
];
|
|
65
|
-
export const TRIAGE_SYSTEM_LINES = [
|
|
66
|
-
"You are a senior developer triaging files in a merge request.",
|
|
67
|
-
"For each file, decide whether it NEEDS_REVIEW (modifies logic, functionality, security, or performance) or can be SKIPPED (cosmetic-only: formatting, comments, renaming for clarity, docs, auto-generated files).",
|
|
68
|
-
"",
|
|
69
|
-
"Also produce a concise summary (2-4 sentences) of the entire merge request: what it does and which areas it touches.",
|
|
70
|
-
"",
|
|
71
|
-
"Respond with a JSON object (no markdown fences) in this exact schema:",
|
|
72
|
-
'{ "summary": "<MR summary>", "files": [{ "path": "<file path>", "verdict": "NEEDS_REVIEW" | "SKIP" }] }',
|
|
73
|
-
"",
|
|
74
|
-
"Rules:",
|
|
75
|
-
"- When in doubt, verdict is NEEDS_REVIEW.",
|
|
76
|
-
"- Deleted files are SKIP unless the deletion could break dependents.",
|
|
77
|
-
"- New files containing logic are NEEDS_REVIEW.",
|
|
78
|
-
"- Test-only files are SKIP unless they cover security-critical or complex logic.",
|
|
79
|
-
"- Config/CI/docs files are SKIP unless they modify build targets, env vars, or secrets.",
|
|
80
|
-
];
|
|
81
|
-
export const FILE_REVIEW_SYSTEM_LINES = [
|
|
82
|
-
"You are a senior developer reviewing a single file's git diff for correctness bugs, security issues, and performance regressions.",
|
|
83
|
-
"Return at most 2 findings for this file. Prefer no finding over a weakly supported one.",
|
|
84
|
-
"",
|
|
85
|
-
"SCOPE:",
|
|
86
|
-
"- Only flag issues introduced by this diff.",
|
|
87
|
-
"- Focus on added/changed lines (`+`). Context lines (` `) and removed lines (`-`) are reference only.",
|
|
88
|
-
"- Do not comment on untouched code unless required for a proven bug path.",
|
|
89
|
-
"- If you cannot point to a concrete problematic added/changed line and explain in one sentence why it is definitely wrong, skip the finding.",
|
|
90
|
-
"",
|
|
91
|
-
"ACCURACY:",
|
|
92
|
-
"- Only report issues directly supported by diff lines and/or visible imports/exports.",
|
|
93
|
-
"- Do not invent behavior, fields, or code paths not visible in evidence.",
|
|
94
|
-
"- Removed (`-`) lines are historical; do not claim current usage based solely on them.",
|
|
95
|
-
"- If a concept is consistently renamed (e.g. `*Type` -> `*Percent`), do not flag missing old-name checks without conflicting evidence in current (`+`) lines.",
|
|
96
|
-
"- Do not report `missing dependency` when the dependency is removed from both usage and declarations.",
|
|
97
|
-
"- If any part of the execution path depends on code you cannot see (truncated sections/missing files), treat this as uncertainty and do not report a finding.",
|
|
98
|
-
"",
|
|
99
|
-
"ANTI-HALLUCINATION (mandatory):",
|
|
100
|
-
"- SYNTAX ERRORS: Do not claim syntax errors unless you can quote the exact invalid token. Count parentheses/brackets on the actual line.",
|
|
101
|
-
"- MISSING EXPORTS/FUNCTIONS: Do not report missing functions/variables/types/exports unless there is direct usage in added lines and full relevant context is visible. If truncated, you CANNOT claim missing.",
|
|
102
|
-
"- UNDEFINED VARIABLES: Do not claim undefined unless the variable is absent from visible lines in the same scope.",
|
|
103
|
-
"- SIGNATURE CHANGES: A changed signature is NOT a bug. Only flag if a caller in the diff passes wrong arguments.",
|
|
104
|
-
"- REFACTORING: Consistent rename/replace across files is intentional. Do not flag it without contradictory evidence.",
|
|
105
|
-
"- If you are not sure it is a real bug introduced by added/changed lines, do not report it.",
|
|
106
|
-
'- When in doubt between "some issue" and "No issues found.", choose "No issues found."',
|
|
107
|
-
"",
|
|
108
|
-
"SELF-CHECK before each finding: re-read cited lines; if interpretation depends on missing context, drop it.",
|
|
109
|
-
"",
|
|
110
|
-
"PRIORITY: (1) correctness (typo, wrong var, missing await, off-by-one), (2) security (secrets, unsafe eval, unvalidated input), (3) perf regressions (N+1 queries, unbounded loops, missing pagination).",
|
|
111
|
-
"",
|
|
112
|
-
"SEVERITY:",
|
|
113
|
-
"- [high] = deterministic runtime or security issue with a concrete execution path visible in the diff.",
|
|
114
|
-
"- [medium] = well-supported but probabilistic issue.",
|
|
115
|
-
"",
|
|
116
|
-
"QUICK CHECKS:",
|
|
117
|
-
"- Compare added function/method calls against imports/exports for spelling mismatches.",
|
|
118
|
-
"- Flag identifier typos only when a clearly similar identifier exists in the same hunk/file.",
|
|
119
|
-
"- Do not infer typos from imagined names.",
|
|
120
|
-
"- Check changes to exported function signatures, shared types, and global data structures for cross-file breakage.",
|
|
121
|
-
"",
|
|
122
|
-
"OUTPUT FORMAT:",
|
|
123
|
-
"- Each finding must use this 4-line markdown block:",
|
|
124
|
-
"- `- [high|medium] <title>`",
|
|
125
|
-
"- ` File: <path>`",
|
|
126
|
-
"- ` Line: ~<N>`",
|
|
127
|
-
"- ` Why: <one concise sentence with key evidence>`",
|
|
128
|
-
"- No headings, no praise, no code blocks. Do not summarize what changed.",
|
|
129
|
-
'- If no confirmed issues: exactly "No issues found."',
|
|
130
|
-
"- GitLab-flavoured markdown.",
|
|
131
|
-
];
|
|
2
|
+
import { FILE_REVIEW_SYSTEM_LINES, MAIN_SYSTEM_LINES, } from "./templates/review-system.js";
|
|
3
|
+
import { TRIAGE_SYSTEM_LINES } from "./templates/triage-system.js";
|
|
132
4
|
export const buildMainSystemMessages = () => [
|
|
133
5
|
{
|
|
134
6
|
role: "system",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export function buildConsolidateSystemLines(maxFindings) {
|
|
3
|
+
return [
|
|
4
|
+
"You consolidate per-file code review findings into a final ranked list.",
|
|
5
|
+
`Select the top ${maxFindings} most important findings. Deduplicate overlapping issues.`,
|
|
6
|
+
"Preserve this exact per-finding markdown block:",
|
|
7
|
+
"`- [high|medium] <title>`",
|
|
8
|
+
"` File: <path>`",
|
|
9
|
+
"` Line: ~<N>`",
|
|
10
|
+
"` Why: <one concise sentence with key evidence>`",
|
|
11
|
+
"Rank by: (1) [high] before [medium], (2) correctness > security > perf.",
|
|
12
|
+
"Do not add new findings. Do not add headings, summaries, or commentary.",
|
|
13
|
+
"Drop any finding that: claims a syntax error without quoting the invalid token, claims a function/variable is missing without concrete proof, or flags a refactoring rename as a bug.",
|
|
14
|
+
`If fewer than ${maxFindings} findings exist, return all of them.`,
|
|
15
|
+
'If all findings are low quality or dubious after dedup, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
16
|
+
"GitLab-flavoured markdown.",
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
export function buildVerificationSystemLines(maxFindings) {
|
|
20
|
+
return [
|
|
21
|
+
"You are a skeptical verifier of a merge request review.",
|
|
22
|
+
"Your job is to remove weak, speculative, or unsupported findings from the draft list.",
|
|
23
|
+
"Do not add new findings. Keep, rewrite for clarity, or remove existing findings only.",
|
|
24
|
+
"A finding can stay only if it is directly supported by evidence from the per-file findings.",
|
|
25
|
+
"If confidence is not high, drop the finding.",
|
|
26
|
+
"Preserve this exact per-finding markdown block:",
|
|
27
|
+
"`- [high|medium] <title>`",
|
|
28
|
+
"` File: <path>`",
|
|
29
|
+
"` Line: ~<N>`",
|
|
30
|
+
"` Why: <one concise sentence with key evidence>`",
|
|
31
|
+
"Do not add headings, summaries, or extra commentary.",
|
|
32
|
+
`Return at most ${maxFindings} findings.`,
|
|
33
|
+
'If no findings survive verification, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
34
|
+
"GitLab-flavoured markdown.",
|
|
35
|
+
];
|
|
36
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export const MAIN_SYSTEM_LINES = [
|
|
3
|
+
"You are an AI code reviewer for pull requests.",
|
|
4
|
+
"Find only real bugs introduced by the diff.",
|
|
5
|
+
"Return at most 3 findings. Prefer no finding over a weak one.",
|
|
6
|
+
"",
|
|
7
|
+
"Rules:",
|
|
8
|
+
"- Focus on changed lines.",
|
|
9
|
+
"- Ignore style, refactoring suggestions, and general best practices.",
|
|
10
|
+
"- If uncertain, use tools: get_file_at_ref and grep_repository.",
|
|
11
|
+
"- Report only issues clearly visible in diff or verified by tools.",
|
|
12
|
+
'- If uncertain after checking, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
13
|
+
"",
|
|
14
|
+
"Severity:",
|
|
15
|
+
"- [high]: deterministic runtime/security breakage with clear path.",
|
|
16
|
+
"- [medium]: likely bug with strong evidence.",
|
|
17
|
+
"",
|
|
18
|
+
"Output format (strict):",
|
|
19
|
+
"- `- [high|medium] <title>`",
|
|
20
|
+
"- ` File: <path>`",
|
|
21
|
+
"- ` Line: ~<N>`",
|
|
22
|
+
"- ` Why: <one concise sentence with evidence>`",
|
|
23
|
+
'- If no issues: exactly "No confirmed bugs or high-value optimizations found."',
|
|
24
|
+
];
|
|
25
|
+
export const FILE_REVIEW_SYSTEM_LINES = [
|
|
26
|
+
"You are an AI reviewer for a single-file diff.",
|
|
27
|
+
"Find only real bugs introduced by changed lines.",
|
|
28
|
+
"Return at most 2 findings. Prefer no finding over a weak one.",
|
|
29
|
+
"",
|
|
30
|
+
"Rules:",
|
|
31
|
+
"- Focus on changed lines only.",
|
|
32
|
+
"- Ignore style/refactor/general improvement comments.",
|
|
33
|
+
"- If uncertain, use tools: get_file_at_ref and grep_repository.",
|
|
34
|
+
"- Report only issues clearly visible in diff or verified by tools.",
|
|
35
|
+
'- If uncertain after checking, return exactly: "No issues found."',
|
|
36
|
+
"",
|
|
37
|
+
"Severity:",
|
|
38
|
+
"- [high]: deterministic runtime/security breakage with clear path.",
|
|
39
|
+
"- [medium]: likely bug with strong evidence.",
|
|
40
|
+
"",
|
|
41
|
+
"Output format (strict):",
|
|
42
|
+
"- `- [high|medium] <title>`",
|
|
43
|
+
"- ` File: <path>`",
|
|
44
|
+
"- ` Line: ~<N>`",
|
|
45
|
+
"- ` Why: <one concise sentence with evidence>`",
|
|
46
|
+
'- If no issues: exactly "No issues found."',
|
|
47
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export const TRIAGE_SYSTEM_LINES = [
|
|
3
|
+
"You are a senior developer triaging files in a merge request.",
|
|
4
|
+
"For each file, decide whether it NEEDS_REVIEW (modifies logic, functionality, security, or performance) or can be SKIPPED (cosmetic-only: formatting, comments, renaming for clarity, docs, auto-generated files).",
|
|
5
|
+
"",
|
|
6
|
+
"Also produce a concise summary (2-4 sentences) of the entire merge request: what it does and which areas it touches.",
|
|
7
|
+
"",
|
|
8
|
+
"Respond with a JSON object (no markdown fences) in this exact schema:",
|
|
9
|
+
'{ "summary": "<MR summary>", "files": [{ "path": "<file path>", "verdict": "NEEDS_REVIEW" | "SKIP" }] }',
|
|
10
|
+
"",
|
|
11
|
+
"Rules:",
|
|
12
|
+
"- When in doubt, verdict is NEEDS_REVIEW.",
|
|
13
|
+
"- Deleted files are SKIP unless the deletion could break dependents.",
|
|
14
|
+
"- New files containing logic are NEEDS_REVIEW.",
|
|
15
|
+
"- Test-only files are SKIP unless they cover security-critical or complex logic.",
|
|
16
|
+
"- Config/CI/docs files are SKIP unless they modify build targets, env vars, or secrets.",
|
|
17
|
+
];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export function buildMainReviewUserContent(params) {
|
|
3
|
+
const { stats, toolNote, changesText } = params;
|
|
4
|
+
return [
|
|
5
|
+
`Review the following code changes (git diff format). ${stats}`,
|
|
6
|
+
toolNote,
|
|
7
|
+
"",
|
|
8
|
+
"Changes:",
|
|
9
|
+
changesText || "(no changes provided)",
|
|
10
|
+
"",
|
|
11
|
+
"Produce your review now. Follow the system instructions strictly.",
|
|
12
|
+
].join("\n");
|
|
13
|
+
}
|
|
14
|
+
export function buildTriageUserContent(changes) {
|
|
15
|
+
const fileEntries = changes.map((c) => {
|
|
16
|
+
const flags = [];
|
|
17
|
+
if (c.new_file)
|
|
18
|
+
flags.push("new");
|
|
19
|
+
if (c.deleted_file)
|
|
20
|
+
flags.push("deleted");
|
|
21
|
+
if (c.renamed_file)
|
|
22
|
+
flags.push("renamed");
|
|
23
|
+
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
24
|
+
const snippet = c.diff.slice(0, 300);
|
|
25
|
+
const truncNote = c.diff.length > 300 ? "..." : "";
|
|
26
|
+
return `### ${c.path}${flagStr}\n\`\`\`\n${snippet}${truncNote}\n\`\`\``;
|
|
27
|
+
});
|
|
28
|
+
return `Triage these ${changes.length} file(s):\n\n${fileEntries.join("\n\n")}`;
|
|
29
|
+
}
|
|
30
|
+
export function buildFileReviewUserContent(params) {
|
|
31
|
+
const { filePath, fileDiff, summary, otherChangedFiles, toolNote } = params;
|
|
32
|
+
const otherFilesNote = otherChangedFiles.length > 0
|
|
33
|
+
? `\nOther files changed in this MR: ${otherChangedFiles.join(", ")}`
|
|
34
|
+
: "";
|
|
35
|
+
return [
|
|
36
|
+
`MR Summary: ${summary}`,
|
|
37
|
+
otherFilesNote,
|
|
38
|
+
"",
|
|
39
|
+
toolNote,
|
|
40
|
+
"",
|
|
41
|
+
`File: ${filePath}`,
|
|
42
|
+
"Diff:",
|
|
43
|
+
fileDiff,
|
|
44
|
+
"",
|
|
45
|
+
"Review this file now.",
|
|
46
|
+
].join("\n");
|
|
47
|
+
}
|
|
48
|
+
export function buildConsolidateUserContent(params) {
|
|
49
|
+
const { summary, findingsText, maxFindings } = params;
|
|
50
|
+
return [
|
|
51
|
+
`MR Summary: ${summary}`,
|
|
52
|
+
"",
|
|
53
|
+
"Per-file findings:",
|
|
54
|
+
findingsText,
|
|
55
|
+
"",
|
|
56
|
+
`Return the top ${maxFindings} findings in the required bullet format.`,
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
|
59
|
+
export function buildVerificationUserContent(params) {
|
|
60
|
+
const { summary, findingsText, consolidatedFindings } = params;
|
|
61
|
+
return [
|
|
62
|
+
`MR Summary: ${summary}`,
|
|
63
|
+
"",
|
|
64
|
+
"Per-file findings (evidence pool):",
|
|
65
|
+
findingsText,
|
|
66
|
+
"",
|
|
67
|
+
"Draft consolidated findings to verify:",
|
|
68
|
+
consolidatedFindings,
|
|
69
|
+
"",
|
|
70
|
+
"Return only the verified final findings.",
|
|
71
|
+
].join("\n");
|
|
72
|
+
}
|