@krotovm/gitlab-ai-review 1.0.42 → 1.0.43

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/README.md CHANGED
@@ -76,7 +76,7 @@ Set these in your project/group CI settings:
76
76
  - `OPENAI_BASE_URL` (optional, for OpenAI-compatible providers/proxies)
77
77
  - `AI_MODEL` (optional, default: `gpt-4o-mini`; example: `gpt-4o`)
78
78
  - `AI_PROMPT_PROFILE` (optional, default: `default`; one of `default` \| `weak`). Use `weak` for small or heavily-quantized models (≤ ~7B, local Ollama, etc.). The `weak` profile uses shorter system prompts, positive rules instead of negations, and inline few-shot examples for triage / per-file review / consolidation / verification, which dramatically improves output-format adherence on weak models. When the variable is not set, the profile is auto-detected: if the triage pass returns unparseable JSON with `default` prompts, triage is retried once with `weak` and, on success, the whole run continues with it. Set the variable explicitly to pin a profile and disable auto-detection.
79
- - `PROJECT_ACCESS_TOKEN` (optional for public projects, but required for most private projects; token with `api` scope)
79
+ - `PROJECT_ACCESS_TOKEN` (required; project or personal access token with `api` scope — `CI_JOB_TOKEN` can't post MR comments or use the search API)
80
80
  - `GITLAB_TOKEN` (optional alias for `PROJECT_ACCESS_TOKEN`)
81
81
  - `AI_REVIEW_CONCURRENCY` (optional) — same as `--max-review-concurrency`, handy as a CI/CD variable; the flag wins when both are set.
82
82
  - `AI_REVIEW_ARTIFACT_HTML_FILE` (optional, default: `ai-review-report.html`; used with `--include-artifacts`)
@@ -88,7 +88,7 @@ GitLab provides these automatically in Merge Request pipelines:
88
88
  - `CI_API_V4_URL`
89
89
  - `CI_PROJECT_ID`
90
90
  - `CI_MERGE_REQUEST_IID`
91
- - `CI_JOB_TOKEN` (used only when `PROJECT_ACCESS_TOKEN` is not provided)
91
+ - `CI_MERGE_REQUEST_PROJECT_ID` (the MR's target project; used instead of `CI_PROJECT_ID`, so MRs from forks work)
92
92
 
93
93
  ## Flags
94
94
 
@@ -3,7 +3,7 @@ import OpenAI from "openai";
3
3
  import { buildAnswer, buildConsolidatePrompt, buildFileReviewPrompt, buildPrompt, buildTriagePrompt, buildVerificationPrompt, DEFAULT_PROMPT_PROFILE, extractCompletionText, isEmptyReviewBody, NO_FINDINGS_SENTENCE, parseTriageResponseDetailed, parseTriageResponse, } from "../prompt/index.js";
4
4
  import { fetchFileAtRef, searchRepository, } from "../gitlab/services.js";
5
5
  import { parseReviewFindings, truncateWithMarker } from "../prompt/utils.js";
6
- import { logToolUsageMinimal, MAX_FILE_TOOL_ROUNDS, MAX_TOOL_ROUNDS, MAX_VERIFICATION_TOOL_ROUNDS, TOOL_NAME_GET_FILE, TOOL_NAME_GREP, } from "./tooling.js";
6
+ import { logToolFailure, logToolUsageMinimal, MAX_FILE_TOOL_ROUNDS, MAX_TOOL_ROUNDS, MAX_VERIFICATION_TOOL_ROUNDS, TOOL_NAME_GET_FILE, TOOL_NAME_GREP, } from "./tooling.js";
7
7
  /** Hard deadline per model call, retries included. Must exceed the gateway's own
8
8
  * proxy timeout so the SDK's 5xx retries stay the first line of defense. */
9
9
  const COMPLETION_TIMEOUT_MS = 180_000;
@@ -14,6 +14,7 @@ let streamUsageSupported = true;
14
14
  * round, so oversized results multiply prefill time on self-hosted models. */
15
15
  const MAX_TOOL_FILE_CHARS = 12_000;
16
16
  const MAX_TOOL_GREP_CHARS = 800;
17
+ const MAX_TOOL_GREP_RESULTS = 10;
17
18
  function buildTriageDecisions(params) {
18
19
  const { changes, triageResult } = params;
19
20
  const triageMap = new Map(triageResult.files.map((f) => [f.path, f]));
@@ -149,7 +150,7 @@ function buildReviewMetadata(changes, refs) {
149
150
  ],
150
151
  }, null, 2);
151
152
  }
152
- async function handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers) {
153
+ async function handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers, logStep) {
153
154
  try {
154
155
  const parsed = JSON.parse(argsRaw);
155
156
  const path = parsed.path?.trim();
@@ -167,10 +168,12 @@ async function handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers) {
167
168
  ref,
168
169
  });
169
170
  if (fileText instanceof Error) {
171
+ logToolFailure(logStep, TOOL_NAME_GET_FILE, fileText);
170
172
  return JSON.stringify({
171
173
  ok: false,
172
174
  path,
173
175
  ref,
176
+ status: fileText.statusCode,
174
177
  error: fileText.message,
175
178
  });
176
179
  }
@@ -183,46 +186,57 @@ async function handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers) {
183
186
  });
184
187
  }
185
188
  catch (error) {
189
+ logToolFailure(logStep, TOOL_NAME_GET_FILE, error);
186
190
  return JSON.stringify({
187
191
  ok: false,
188
- error: `Failed to parse tool arguments: ${String(error?.message ?? error)}`,
192
+ error: `Tool call failed: ${String(error?.message ?? error)}`,
189
193
  raw: argsRaw,
190
194
  });
191
195
  }
192
196
  }
193
- async function handleGrepTool(argsRaw, defaultRef, gitLabProjectApiUrl, headers, projectId) {
197
+ async function handleGrepTool(argsRaw, refs, gitLabProjectApiUrl, headers, logStep) {
194
198
  try {
195
199
  const parsed = JSON.parse(argsRaw);
196
200
  const query = parsed.query?.trim();
197
201
  if (!query)
198
202
  return JSON.stringify({ ok: false, error: "query is required." });
199
- const ref = parsed.ref?.trim() || defaultRef;
203
+ // GitLab search answers 200 [] for unknown refs, so only the MR's own refs are searched.
204
+ const ref = parsed.ref?.trim() === refs.base ? refs.base : refs.head;
200
205
  const results = await searchRepository({
201
206
  gitLabProjectApiUrl: gitLabProjectApiUrl,
202
207
  headers,
203
208
  query,
204
209
  ref,
205
- projectId,
206
210
  });
207
211
  if (results instanceof Error) {
212
+ logToolFailure(logStep, TOOL_NAME_GREP, results);
208
213
  return JSON.stringify({
209
214
  ok: false,
210
215
  query,
211
216
  ref,
217
+ status: results.statusCode,
212
218
  error: results.message,
213
219
  });
214
220
  }
215
- const trimmed = results.map((r) => ({
221
+ // GitLab lists file-name matches (file head, startline 1) before content matches;
222
+ // rank hits that contain the query first so they aren't crowded out.
223
+ const needle = query.toLowerCase();
224
+ const hasNeedle = (r) => (r.data ?? "").toLowerCase().includes(needle);
225
+ const trimmed = results
226
+ .sort((a, b) => Number(hasNeedle(b)) - Number(hasNeedle(a)))
227
+ .slice(0, MAX_TOOL_GREP_RESULTS)
228
+ .map((r) => ({
216
229
  path: r.path,
217
230
  startline: r.startline,
218
- data: r.data.slice(0, MAX_TOOL_GREP_CHARS),
231
+ data: (r.data ?? "").slice(0, MAX_TOOL_GREP_CHARS),
219
232
  }));
220
233
  return JSON.stringify({ ok: true, query, ref, matches: trimmed });
221
234
  }
222
235
  catch (error) {
236
+ logToolFailure(logStep, TOOL_NAME_GREP, error);
223
237
  return JSON.stringify({
224
238
  ok: false,
225
- error: `Failed to parse tool arguments: ${String(error?.message ?? error)}`,
239
+ error: `Tool call failed: ${String(error?.message ?? error)}`,
226
240
  raw: argsRaw,
227
241
  });
228
242
  }
@@ -241,8 +255,8 @@ async function mapWithConcurrency(items, concurrency, fn) {
241
255
  await Promise.all(workers);
242
256
  return results;
243
257
  }
244
- export async function reviewMergeRequestWithTools(params) {
245
- const { openaiInstance, aiModel, promptLimits, changes, refs, gitLabProjectApiUrl, projectId, headers, forceTools, promptProfile = DEFAULT_PROMPT_PROFILE, loggers, debugDumpFile, debugRecordWriter, } = params;
258
+ async function reviewMergeRequestWithTools(params) {
259
+ const { openaiInstance, aiModel, promptLimits, changes, refs, gitLabProjectApiUrl, headers, forceTools, promptProfile = DEFAULT_PROMPT_PROFILE, loggers, debugDumpFile, debugRecordWriter, } = params;
246
260
  const { logDebug, logStep } = loggers;
247
261
  logStep(`Single-pass review started for ${changes.length} file(s) (fallback mode).`);
248
262
  const messages = buildPrompt({
@@ -343,10 +357,10 @@ export async function reviewMergeRequestWithTools(params) {
343
357
  logToolUsageMinimal(logStep, toolName, argsRaw);
344
358
  let toolContent;
345
359
  if (toolName === TOOL_NAME_GET_FILE) {
346
- toolContent = await handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers);
360
+ toolContent = await handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers, logStep);
347
361
  }
348
362
  else if (toolName === TOOL_NAME_GREP) {
349
- toolContent = await handleGrepTool(argsRaw, refs.head, gitLabProjectApiUrl, headers, projectId);
363
+ toolContent = await handleGrepTool(argsRaw, refs, gitLabProjectApiUrl, headers, logStep);
350
364
  }
351
365
  else {
352
366
  toolContent = JSON.stringify({
@@ -390,7 +404,7 @@ export async function reviewMergeRequestWithTools(params) {
390
404
  return buildAnswer(finalCompletion);
391
405
  }
392
406
  async function runFileReviewWithTools(params) {
393
- const { openaiInstance, aiModel, filePath, fileDiff, summary, otherChangedFiles, refs, gitLabProjectApiUrl, projectId, headers, forceTools, promptProfile, loggers, debugDumpFile, debugRecordWriter, } = params;
407
+ const { openaiInstance, aiModel, filePath, fileDiff, summary, otherChangedFiles, refs, gitLabProjectApiUrl, headers, forceTools, promptProfile, loggers, debugDumpFile, debugRecordWriter, } = params;
394
408
  const { logDebug, logStep } = loggers;
395
409
  const messages = buildFileReviewPrompt({
396
410
  filePath,
@@ -487,10 +501,10 @@ async function runFileReviewWithTools(params) {
487
501
  logToolUsageMinimal(logStep, toolName, argsRaw, filePath);
488
502
  let toolContent;
489
503
  if (toolName === TOOL_NAME_GET_FILE) {
490
- toolContent = await handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers);
504
+ toolContent = await handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers, logStep);
491
505
  }
492
506
  else if (toolName === TOOL_NAME_GREP) {
493
- toolContent = await handleGrepTool(argsRaw, refs.head, gitLabProjectApiUrl, headers, projectId);
507
+ toolContent = await handleGrepTool(argsRaw, refs, gitLabProjectApiUrl, headers, logStep);
494
508
  }
495
509
  else {
496
510
  toolContent = JSON.stringify({
@@ -537,7 +551,7 @@ function draftHasStructuredFindings(consolidatedText) {
537
551
  return /-\s*\[(?:high|medium)\]/i.test(consolidatedText);
538
552
  }
539
553
  async function runVerificationWithTools(params) {
540
- const { openaiInstance, aiModel, baseMessages, refs, gitLabProjectApiUrl, projectId, headers, forceTools, consolidatedDraft, loggers, debugDumpFile, debugRecordWriter, } = params;
554
+ const { openaiInstance, aiModel, baseMessages, refs, gitLabProjectApiUrl, headers, forceTools, consolidatedDraft, loggers, debugDumpFile, debugRecordWriter, } = params;
541
555
  const { logDebug, logStep } = loggers;
542
556
  const messages = [...baseMessages];
543
557
  const tools = [
@@ -627,10 +641,10 @@ async function runVerificationWithTools(params) {
627
641
  logToolUsageMinimal(logStep, toolName, argsRaw, "(verify)");
628
642
  let toolContent;
629
643
  if (toolName === TOOL_NAME_GET_FILE) {
630
- toolContent = await handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers);
644
+ toolContent = await handleGetFileTool(argsRaw, gitLabProjectApiUrl, headers, logStep);
631
645
  }
632
646
  else if (toolName === TOOL_NAME_GREP) {
633
- toolContent = await handleGrepTool(argsRaw, refs.head, gitLabProjectApiUrl, headers, projectId);
647
+ toolContent = await handleGrepTool(argsRaw, refs, gitLabProjectApiUrl, headers, logStep);
634
648
  }
635
649
  else {
636
650
  toolContent = JSON.stringify({
@@ -672,7 +686,7 @@ async function runVerificationWithTools(params) {
672
686
  });
673
687
  }
674
688
  export async function reviewMergeRequestMultiPass(params) {
675
- const { openaiInstance, aiModel, promptLimits, triageDiffChars, changes, refs, gitLabProjectApiUrl, projectId, headers, maxFindings, reviewConcurrency, forceTools, promptProfile = DEFAULT_PROMPT_PROFILE, allowProfileAutoDemote = false, loggers, debugDumpFile, debugRecordWriter, } = params;
689
+ const { openaiInstance, aiModel, promptLimits, triageDiffChars, changes, refs, gitLabProjectApiUrl, headers, maxFindings, reviewConcurrency, forceTools, promptProfile = DEFAULT_PROMPT_PROFILE, allowProfileAutoDemote = false, loggers, debugDumpFile, debugRecordWriter, } = params;
676
690
  const { logStep } = loggers;
677
691
  let effectiveProfile = promptProfile;
678
692
  logStep(`Pass 1/4: triaging ${changes.length} file(s) ` +
@@ -773,7 +787,6 @@ export async function reviewMergeRequestMultiPass(params) {
773
787
  changes,
774
788
  refs,
775
789
  gitLabProjectApiUrl,
776
- projectId,
777
790
  headers,
778
791
  forceTools,
779
792
  promptProfile: effectiveProfile,
@@ -821,7 +834,6 @@ export async function reviewMergeRequestMultiPass(params) {
821
834
  otherChangedFiles: otherFiles,
822
835
  refs,
823
836
  gitLabProjectApiUrl,
824
- projectId,
825
837
  headers,
826
838
  forceTools,
827
839
  promptProfile: effectiveProfile,
@@ -909,7 +921,6 @@ export async function reviewMergeRequestMultiPass(params) {
909
921
  baseMessages: verificationMessages,
910
922
  refs,
911
923
  gitLabProjectApiUrl,
912
- projectId,
913
924
  headers,
914
925
  forceTools,
915
926
  consolidatedDraft: consolidatedText,
@@ -27,3 +27,9 @@ export function logToolUsageMinimal(logStep, toolName, argsRaw, contextFile) {
27
27
  const suffix = contextFile ? ` review_file=${contextFile}` : "";
28
28
  logStep(`[tools] ${toolName} args=${argsRaw.slice(0, 120)}${suffix}`);
29
29
  }
30
+ /** Operator-facing line for a failed tool call: GitLab status and request URL when known. */
31
+ export function logToolFailure(logStep, toolName, error) {
32
+ const status = error?.statusCode != null ? ` status=${error.statusCode}` : "";
33
+ const url = typeof error?.cause?.url === "string" ? ` url=${error.cause.url}` : "";
34
+ logStep(`[tools] ${toolName} failed: ${String(error?.message ?? error)}${status}${url}`);
35
+ }
package/dist/cli.js CHANGED
@@ -38,10 +38,10 @@ Env vars:
38
38
  positive rules, and few-shot examples.
39
39
  When unset, an unparseable triage response auto-retries
40
40
  with "weak" and keeps it for the whole run.
41
- PROJECT_ACCESS_TOKEN (optional) GitLab Project/Personal Access Token for API calls (required for most private repos; should have api scope).
41
+ PROJECT_ACCESS_TOKEN (required) GitLab project/personal access token with api scope (alias: GITLAB_TOKEN). CI_JOB_TOKEN can't post MR comments.
42
42
 
43
43
  CI-only env vars (provided by GitLab):
44
- CI_API_V4_URL, CI_PROJECT_ID, CI_MERGE_REQUEST_IID, CI_JOB_TOKEN (only if PROJECT_ACCESS_TOKEN is not set)
44
+ CI_API_V4_URL, CI_PROJECT_ID, CI_MERGE_REQUEST_PROJECT_ID, CI_MERGE_REQUEST_IID
45
45
  `);
46
46
  }
47
47
  const DEBUG_MODE = hasDebugFlag(process.argv);
@@ -107,25 +107,24 @@ async function main() {
107
107
  "CI_PROJECT_ID",
108
108
  "CI_MERGE_REQUEST_IID",
109
109
  ];
110
+ // CI_JOB_TOKEN can't post MR notes or call the search API, so a real token is required.
110
111
  if (projectAccessToken == null)
111
- gitlabRequired.push("CI_JOB_TOKEN");
112
+ gitlabRequired.push("PROJECT_ACCESS_TOKEN");
112
113
  const envs = requireEnvs(gitlabRequired);
113
114
  const openaiApiKey = envs["OPENAI_API_KEY"];
114
115
  const ciApiV4Url = envs["CI_API_V4_URL"];
115
- const projectId = envs["CI_PROJECT_ID"];
116
+ // MR endpoints live in the MR's target project; in fork pipelines CI_PROJECT_ID is the fork.
117
+ const projectId = envOrUndefined("CI_MERGE_REQUEST_PROJECT_ID") ?? envs["CI_PROJECT_ID"];
116
118
  const mergeRequestIid = envs["CI_MERGE_REQUEST_IID"];
117
119
  const gitLabProjectApiUrl = new URL(`${ciApiV4Url}/projects/${projectId}`);
118
- const headers = {};
119
- if (projectAccessToken != null)
120
- headers["PRIVATE-TOKEN"] = projectAccessToken;
121
- else
122
- headers["JOB-TOKEN"] = envs["CI_JOB_TOKEN"];
120
+ const headers = {
121
+ "PRIVATE-TOKEN": projectAccessToken,
122
+ };
123
123
  try {
124
124
  logStep("Fetching merge request changes");
125
125
  const mrChanges = await fetchMergeRequestChanges({
126
126
  gitLabProjectApiUrl: gitLabProjectApiUrl,
127
127
  headers,
128
- projectId,
129
128
  mergeRequestIid,
130
129
  });
131
130
  if (mrChanges instanceof Error)
@@ -149,7 +148,6 @@ async function main() {
149
148
  head: mrChanges.diff_refs?.head_sha ?? "HEAD",
150
149
  },
151
150
  gitLabProjectApiUrl: gitLabProjectApiUrl,
152
- projectId,
153
151
  headers,
154
152
  maxFindings,
155
153
  reviewConcurrency,
@@ -164,7 +162,8 @@ async function main() {
164
162
  gitLabProjectApiUrl: gitLabProjectApiUrl,
165
163
  headers,
166
164
  mergeRequestIid,
167
- }, { body: answer });
165
+ note: answer,
166
+ });
168
167
  if (noteRes instanceof Error)
169
168
  throw noteRes;
170
169
  process.stdout.write("Posted AI review comment to merge request.\n");
@@ -1,47 +1,5 @@
1
1
  /** @format */
2
- import OpenAI from "openai";
3
- import { AI_MODEL_TEMPERATURE } from "../prompt/index.js";
4
- import { GitLabError, OpenAIError, } from "./types.js";
5
- export const fetchPreEditFiles = async ({ gitLabProjectApiUrl, headers, changesOldPaths, ref }) => {
6
- const oldFilesRequestUrls = changesOldPaths.map((filePath) => {
7
- const url = new URL(`${gitLabProjectApiUrl}/repository/files/${encodeURIComponent(filePath)}/raw`);
8
- url.searchParams.set("ref", ref);
9
- return url;
10
- });
11
- let oldFiles;
12
- try {
13
- oldFiles = await Promise.allSettled(oldFilesRequestUrls.map(async (url) => {
14
- const res = await fetch(url, { headers: { ...headers } });
15
- if (!res.ok) {
16
- const bodyText = await res.text().catch(() => "");
17
- throw new Error(`Failed to fetch old file: ${url.toString()} (status ${res.status} ${res.statusText}, body: ${bodyText.slice(0, 500)})`);
18
- }
19
- return await res.text();
20
- }));
21
- }
22
- catch (error) {
23
- oldFiles = error;
24
- }
25
- if (oldFiles instanceof Error) {
26
- return new GitLabError({
27
- name: "MISSING_OLD_FILES",
28
- message: "Failed to fetch old files",
29
- cause: {
30
- message: oldFiles.message,
31
- stack: oldFiles.stack,
32
- },
33
- });
34
- }
35
- return oldFiles.reduce((acc, file, index) => {
36
- if (file.status === "fulfilled") {
37
- acc.push({
38
- fileName: changesOldPaths[index],
39
- fileContent: file.value,
40
- });
41
- }
42
- return acc;
43
- }, []);
44
- };
2
+ import { GitLabError, } from "./types.js";
45
3
  export const fetchFileAtRef = async ({ gitLabProjectApiUrl, headers, filePath, ref }) => {
46
4
  const url = new URL(`${gitLabProjectApiUrl}/repository/files/${encodeURIComponent(filePath)}/raw`);
47
5
  url.searchParams.set("ref", ref);
@@ -81,29 +39,7 @@ export const fetchFileAtRef = async ({ gitLabProjectApiUrl, headers, filePath, r
81
39
  }
82
40
  return await res.text();
83
41
  };
84
- export async function generateAICompletion(messages, openaiInstance, aiModel) {
85
- let completion;
86
- try {
87
- completion = await openaiInstance.chat.completions.create({
88
- model: aiModel,
89
- temperature: AI_MODEL_TEMPERATURE,
90
- stream: false,
91
- messages,
92
- });
93
- }
94
- catch (error) {
95
- completion = error;
96
- }
97
- if (completion instanceof Error) {
98
- return new OpenAIError({
99
- name: "MISSING_AI_COMPLETION",
100
- message: "Failed to generate AI completion",
101
- cause: completion,
102
- });
103
- }
104
- return completion;
105
- }
106
- export const postMergeRequestNote = async ({ gitLabProjectApiUrl, headers, mergeRequestIid }, commentPayload) => {
42
+ export const postMergeRequestNote = async ({ gitLabProjectApiUrl, headers, mergeRequestIid, note }) => {
107
43
  const commentUrl = new URL(`${gitLabProjectApiUrl}/merge_requests/${mergeRequestIid}/notes`);
108
44
  let aiComment;
109
45
  try {
@@ -113,7 +49,7 @@ export const postMergeRequestNote = async ({ gitLabProjectApiUrl, headers, merge
113
49
  ...headers,
114
50
  "Content-Type": "application/json",
115
51
  },
116
- body: JSON.stringify(commentPayload),
52
+ body: JSON.stringify({ body: note }),
117
53
  });
118
54
  }
119
55
  catch (error) {
@@ -152,7 +88,8 @@ export const searchRepository = async ({ gitLabProjectApiUrl, headers, query, re
152
88
  url.searchParams.set("scope", "blobs");
153
89
  url.searchParams.set("search", query);
154
90
  url.searchParams.set("ref", ref);
155
- url.searchParams.set("per_page", "10");
91
+ // Name matches come before content matches; the grep tool re-ranks and keeps 10.
92
+ url.searchParams.set("per_page", "50");
156
93
  let res;
157
94
  try {
158
95
  res = await fetch(url, { headers: { ...headers } });
@@ -1,5 +1,3 @@
1
1
  import { BaseError } from '../errors.js';
2
2
  export class GitLabError extends BaseError {
3
3
  }
4
- export class OpenAIError extends BaseError {
5
- }
@@ -12,8 +12,6 @@ export const DEFAULT_PROMPT_LIMITS = {
12
12
  };
13
13
  /** Max chars of each file diff sent to the triage pass (Pass 1). */
14
14
  export const DEFAULT_TRIAGE_DIFF_CHARS = 2000;
15
- export const AI_MODEL_TEMPERATURE = 0.2;
16
- export const AI_MAX_OUTPUT_TOKENS = 600;
17
15
  export const buildPrompt = ({ changes, limits, allowTools = false, profile = DEFAULT_PROMPT_PROFILE, }) => {
18
16
  const effectiveLimits = {
19
17
  ...DEFAULT_PROMPT_LIMITS,
@@ -16,7 +16,3 @@ export const buildFileReviewSystemMessage = (profile = DEFAULT_PROMPT_PROFILE) =
16
16
  role: "system",
17
17
  content: getFileReviewSystemPrompt(profile),
18
18
  });
19
- /** @deprecated kept for backward compatibility — use buildTriageSystemMessage(). */
20
- export const TRIAGE_SYSTEM = buildTriageSystemMessage();
21
- /** @deprecated kept for backward compatibility — use buildFileReviewSystemMessage(). */
22
- export const FILE_REVIEW_SYSTEM = buildFileReviewSystemMessage();
@@ -106,7 +106,3 @@ export function getMainSystemPrompt(profile) {
106
106
  export function getFileReviewSystemPrompt(profile) {
107
107
  return profile === "weak" ? FILE_WEAK : FILE_DEFAULT;
108
108
  }
109
- /** @deprecated kept for backward compatibility — use getMainSystemPrompt("default"). */
110
- export const MAIN_SYSTEM_LINES = MAIN_DEFAULT.split("\n");
111
- /** @deprecated kept for backward compatibility — use getFileReviewSystemPrompt("default"). */
112
- export const FILE_REVIEW_SYSTEM_LINES = FILE_DEFAULT.split("\n");
@@ -42,5 +42,3 @@ Example output (copy this exactly — one line, one JSON object, nothing else):
42
42
  export function getTriageSystemPrompt(profile) {
43
43
  return profile === "weak" ? WEAK : DEFAULT;
44
44
  }
45
- /** @deprecated kept for backward compatibility — use getTriageSystemPrompt("default"). */
46
- export const TRIAGE_SYSTEM_LINES = DEFAULT.split("\n");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@krotovm/gitlab-ai-review",
4
- "version": "1.0.42",
4
+ "version": "1.0.43",
5
5
  "description": "CLI tool to generate AI code reviews for GitLab merge requests.",
6
6
  "main": "dist/cli.js",
7
7
  "bin": {