PRININIT / lib /src /options.js
yaminXwin's picture
feat: implement confidence-based comment routing, severity calibration, token budget truncation, and false-positive suppression rules
4d0586c
Raw
History Blame Contribute Delete
6.97 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AIOptions = exports.PathFilter = exports.Options = void 0;
const info = console.log;
const debug = process.env.LOG_LEVEL === 'debug' ? console.log.bind(console) : () => { };
const minimatch_1 = require("minimatch");
const limits_1 = require("./limits");
class Options {
debug;
disableReview;
disableReleaseNotes;
maxFiles;
reviewSimpleChanges;
reviewCommentLGTM;
pathFilters;
systemMessage;
lightModel;
heavyModel;
modelTemperature;
retries;
timeoutMS;
concurrencyLimit;
githubConcurrencyLimit;
lightTokenLimits;
heavyTokenLimits;
apiBaseUrl;
language;
createRemedyPR;
enableAutoPR; // SECURITY: require explicit opt-in for auto PR creation
strictMode; // When true, posts style/naming issues. When false, skips them to avoid "eslint bot syndrome"
static FREE_TIER_MODELS = [
'openai/gpt-oss-120b:free',
'openai/gpt-oss-20b',
'qwen/qwen3-235b-a22b-2507'
];
// Primary model for paid tier: qwen for everything (review, autofix, plan)
static PAID_PRIMARY_MODEL = 'qwen/qwen3-235b-a22b-2507';
// Paid fallback if qwen fails
static PAID_FALLBACK_MODEL = 'openai/gpt-oss-120b';
static PAID_REVIEW_FALLBACKS = [
'qwen/qwen3-235b-a22b-2507',
'openai/gpt-oss-120b'
];
static PAID_AUTOFIX_FALLBACKS = [
'qwen/qwen3-235b-a22b-2507',
'openai/gpt-oss-120b'
];
static PAID_PLAN_FALLBACKS = [
'qwen/qwen3-235b-a22b-2507',
'openai/gpt-oss-120b'
];
static selectReviewModel(totalLinesChanged) {
return 'qwen/qwen3-235b-a22b-2507';
}
static HEAVY_MODELS = [
'openai/gpt-oss-120b',
'openai/gpt-oss-120b:free',
'qwen/qwen3-235b-a22b-2507',
'openai/gpt-oss-20b'
];
static LIGHT_MODELS = [
'llama-3.1-8b-instant',
'groq/compound',
'groq/compound-mini',
'llama-3.2-11b-vision-preview'
];
static SECURITY_MODELS = [
'openai/gpt-oss-safeguard-20b',
'meta-llama/llama-guard-4-12b',
'meta-llama/llama-prompt-guard-2-86m',
'meta-llama/llama-prompt-guard-2-22m'
];
constructor(debug = true, disableReview = false, disableReleaseNotes = false, maxFiles = '0', reviewSimpleChanges = false, reviewCommentLGTM = false, pathFilters = null, systemMessage = '', lightModel = 'openai/gpt-oss-120b:free', heavyModel = 'openai/gpt-oss-120b:free', modelTemperature = '0.0', retries = '3', timeoutMS = '120000', concurrencyLimit = '6', githubConcurrencyLimit = '6', apiBaseUrl = 'https://api.groq.com/openai/v1', language = 'en-US', createRemedyPR = false, enableAutoPR = false, strictMode = false) {
this.debug = debug;
this.disableReview = disableReview;
this.disableReleaseNotes = disableReleaseNotes;
this.maxFiles = parseInt(maxFiles);
this.reviewSimpleChanges = reviewSimpleChanges;
this.reviewCommentLGTM = reviewCommentLGTM;
this.pathFilters = new PathFilter(pathFilters);
this.systemMessage = systemMessage;
this.lightModel = lightModel;
this.heavyModel = heavyModel;
this.modelTemperature = parseFloat(modelTemperature);
this.retries = parseInt(retries);
this.timeoutMS = parseInt(timeoutMS);
this.concurrencyLimit = parseInt(concurrencyLimit);
this.githubConcurrencyLimit = parseInt(githubConcurrencyLimit);
this.apiBaseUrl = apiBaseUrl;
this.language = language;
this.createRemedyPR = createRemedyPR;
this.enableAutoPR = enableAutoPR;
this.strictMode = strictMode;
this.lightTokenLimits = new limits_1.TokenLimits(this.lightModel);
this.heavyTokenLimits = new limits_1.TokenLimits(this.heavyModel);
}
// print all options using core.info
print() {
info(`debug: ${this.debug}`);
info(`disable_review: ${this.disableReview}`);
info(`disable_release_notes: ${this.disableReleaseNotes}`);
info(`max_files: ${this.maxFiles}`);
info(`review_simple_changes: ${this.reviewSimpleChanges}`);
info(`review_comment_lgtm: ${this.reviewCommentLGTM}`);
info(`path_filters: ${this.pathFilters}`);
info(`system_message: ${this.systemMessage}`);
info(`light_model: ${this.lightModel}`);
info(`heavy_model: ${this.heavyModel}`);
info(`model_temperature: ${this.modelTemperature}`);
info(`retries: ${this.retries}`);
info(`timeout_ms: ${this.timeoutMS}`);
info(`concurrency_limit: ${this.concurrencyLimit}`);
info(`github_concurrency_limit: ${this.githubConcurrencyLimit}`);
info(`summary_token_limits: ${this.lightTokenLimits.string()}`);
info(`review_token_limits: ${this.heavyTokenLimits.string()}`);
info(`api_base_url: ${this.apiBaseUrl}`);
info(`language: ${this.language}`);
info(`create_remedy_pr: ${this.createRemedyPR}`);
info(`enable_auto_pr: ${this.enableAutoPR}`);
info(`strict_mode: ${this.strictMode}`);
}
checkPath(path) {
const ok = this.pathFilters.check(path);
debug(`checking path: ${path} => ${ok}`);
return ok;
}
}
exports.Options = Options;
class PathFilter {
rules;
constructor(rules = null) {
this.rules = [];
if (rules != null) {
for (const rule of rules) {
const trimmed = rule?.trim();
if (trimmed) {
if (trimmed.startsWith('!')) {
this.rules.push([trimmed.substring(1).trim(), true]);
}
else {
this.rules.push([trimmed, false]);
}
}
}
}
}
check(path) {
if (this.rules.length === 0) {
return true;
}
let included = false;
let excluded = false;
let inclusionRuleExists = false;
for (const [rule, exclude] of this.rules) {
if ((0, minimatch_1.minimatch)(path, rule)) {
if (exclude) {
excluded = true;
}
else {
included = true;
}
}
if (!exclude) {
inclusionRuleExists = true;
}
}
return (!inclusionRuleExists || included) && !excluded;
}
}
exports.PathFilter = PathFilter;
class AIOptions {
model;
tokenLimits;
constructor(model = 'openai/gpt-oss-120b:free', tokenLimits = null) {
this.model = model;
if (tokenLimits != null) {
this.tokenLimits = tokenLimits;
}
else {
this.tokenLimits = new limits_1.TokenLimits(model);
}
}
}
exports.AIOptions = AIOptions;
//# sourceMappingURL=options.js.map