feat: 添加Agent审查相关配置项和依赖

新增REVIEW_ENGINE、向量记忆、Reflection/Debate等环境变量;添加@qdrant/js-client-rest和zod-to-json-schema依赖;添加test脚本

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
accelerator
2026-03-01 03:37:30 +00:00
parent 2ce2a5f6a6
commit 611fcf39d5
5 changed files with 128 additions and 9 deletions

View File

@@ -19,3 +19,35 @@ PORT=3000
# 在Linux/Mac终端: openssl rand -hex 32
# 或者在Node.js中: require('crypto').randomBytes(32).toString('hex')
WEBHOOK_SECRET=your_webhook_secret
# Agent审查配置默认关闭开启请设置为agent
REVIEW_ENGINE=legacy
REVIEW_WORKDIR=/tmp/gitea-assistant
REVIEW_MODEL_PLANNER=gpt-4o-mini
REVIEW_MODEL_SPECIALIST=gpt-4o-mini
REVIEW_MODEL_JUDGE=gpt-4o-mini
REVIEW_MAX_PARALLEL_RUNS=2
REVIEW_MAX_FILES_PER_RUN=200
REVIEW_MAX_FILE_CONTENT_CHARS=40000
REVIEW_AUTO_PUBLISH_MIN_CONFIDENCE=0.8
REVIEW_ENABLE_HUMAN_GATE=true
REVIEW_ALLOWED_COMMANDS=git,rg,cat,sed,wc
REVIEW_COMMAND_TIMEOUT_MS=10000
# 向量记忆和学习系统配置(可选,第二阶段功能)
# Qdrant向量数据库URL如果不配置则禁用记忆系统
QDRANT_URL=http://localhost:6333
# 是否启用记忆系统需要先配置QDRANT_URL
ENABLE_MEMORY=false
# Few-shot学习示例数量0-20
FEW_SHOT_EXAMPLES_COUNT=10
# Reflection和Debate配置可选第三阶段功能
# 是否启用Reflection自我批评机制提升审查质量
ENABLE_REFLECTION=false
# Reflection最大轮次1-5
MAX_REFLECTION_ROUNDS=2
# 是否启用Debate多代理辩论机制提升高严重性问题准确性
ENABLE_DEBATE=false
# Debate触发阈值high=仅高严重性, medium=高和中等严重性)
DEBATE_THRESHOLD=high

View File

@@ -1,16 +1,19 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "ai-review",
"dependencies": {
"@hono/zod-validator": "^0.4.3",
"@qdrant/js-client-rest": "^1.16.2",
"axios": "^1.8.3",
"dotenv": "^16.4.7",
"hono": "^4.7.4",
"hono": "^4.11.9",
"lodash-es": "^4.17.21",
"openai": "^4.87.3",
"zod": "^3.24.2",
"zod": "^3.25.1",
"zod-to-json-schema": "^3.25.1",
},
"devDependencies": {
"@types/lodash-es": "^4.17.12",
@@ -27,7 +30,11 @@
"@hono/zod-validator": ["@hono/zod-validator@0.4.3", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.19.1" } }, "sha512-xIgMYXDyJ4Hj6ekm9T9Y27s080Nl9NXHcJkOvkXPhubOLj8hZkOL8pDnnXfvCf5xEE8Q4oMFenQUZZREUY2gqQ=="],
"@types/lodash": ["@types/lodash@4.17.16", "", {}, "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g=="],
"@qdrant/js-client-rest": ["@qdrant/js-client-rest@1.16.2", "", { "dependencies": { "@qdrant/openapi-typescript-fetch": "1.2.6", "undici": "^6.0.0" }, "peerDependencies": { "typescript": ">=4.7" } }, "sha512-Zm4wEZURrZ24a+Hmm4l1QQYjiz975Ep3vF0yzWR7ICGcxittNz47YK2iBOk8kb8qseCu8pg7WmO1HOIsO8alvw=="],
"@qdrant/openapi-typescript-fetch": ["@qdrant/openapi-typescript-fetch@1.2.6", "", {}, "sha512-oQG/FejNpItrxRHoyctYvT3rwGZOnK4jr3JdppO/c78ktDvkWiPXPHNsrDf33K9sZdRb6PR7gi4noIapu5q4HA=="],
"@types/lodash": ["@types/lodash@4.17.23", "", {}, "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA=="],
"@types/lodash-es": ["@types/lodash-es@4.17.12", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ=="],
@@ -117,7 +124,7 @@
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"hono": ["hono@4.11.9", "", {}, "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ=="],
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
@@ -131,7 +138,7 @@
"js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="],
"lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="],
"lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
@@ -183,6 +190,8 @@
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"undici": ["undici@6.23.0", "", {}, "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
"web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="],
@@ -193,7 +202,9 @@
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
"@types/node-fetch/@types/node": ["@types/node@18.19.80", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ=="],

5
check-engine.js Normal file
View File

@@ -0,0 +1,5 @@
const a = require('./dist/review/engine');
const b = require('@/review/engine');
console.log('same?', a.reviewEngine === b.reviewEngine);
console.log('a file', require.resolve('./dist/review/engine'));
console.log('b file', require.resolve('@/review/engine'));

View File

@@ -7,12 +7,14 @@
},
"dependencies": {
"@hono/zod-validator": "^0.4.3",
"@qdrant/js-client-rest": "^1.16.2",
"axios": "^1.8.3",
"dotenv": "^16.4.7",
"hono": "^4.7.4",
"hono": "^4.11.9",
"lodash-es": "^4.17.21",
"openai": "^4.87.3",
"zod": "^3.24.2"
"zod": "^3.25.1",
"zod-to-json-schema": "^3.25.1"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12",
@@ -30,7 +32,8 @@
"build": "rm -rf dist && tsc",
"start": "bun run src/index.ts",
"start:prod": "bun run dist/index.js",
"lint": "tslint -c tslint.json src/**/*.ts"
"lint": "tslint -c tslint.json src/**/*.ts",
"test": "bun test"
},
"keywords": [
"code-review",

View File

@@ -6,6 +6,7 @@ config();
// 判断是否为开发环境
const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV;
const defaultAllowedReviewCommands = ['git', 'rg', 'cat', 'sed', 'wc'];
// 环境变量验证模式
const envSchema = z.object({
@@ -32,6 +33,46 @@ const envSchema = z.object({
// 管理后台配置
ADMIN_PASSWORD: z.string().default('password'),
JWT_SECRET: z.string().default('a-secure-secret-for-jwt'),
// Agent审查配置
REVIEW_ENGINE: z.enum(['legacy', 'agent']).default('legacy'),
REVIEW_WORKDIR: z.string().default('/tmp/gitea-assistant'),
REVIEW_MODEL_PLANNER: z.string().default('gpt-4o-mini'),
REVIEW_MODEL_SPECIALIST: z.string().default('gpt-4o-mini'),
REVIEW_MODEL_JUDGE: z.string().default('gpt-4o-mini'),
REVIEW_MAX_PARALLEL_RUNS: z.coerce.number().int().min(1).max(8).default(2),
REVIEW_MAX_FILES_PER_RUN: z.coerce.number().int().min(1).max(1000).default(200),
REVIEW_MAX_FILE_CONTENT_CHARS: z.coerce.number().int().min(1000).max(1_000_000).default(40_000),
REVIEW_AUTO_PUBLISH_MIN_CONFIDENCE: z.coerce.number().min(0).max(1).default(0.8),
REVIEW_ENABLE_HUMAN_GATE: z
.enum(['true', 'false'])
.default('true')
.transform((value) => value === 'true'),
REVIEW_ALLOWED_COMMANDS: z.string().default(defaultAllowedReviewCommands.join(',')),
REVIEW_COMMAND_TIMEOUT_MS: z.coerce.number().int().min(1000).max(300000).default(10000),
// 向量记忆和学习系统配置
QDRANT_URL: z.preprocess(
(val) => (typeof val === 'string' && val.trim() === '' ? undefined : val),
z.string().url().optional()
),
ENABLE_MEMORY: z
.enum(['true', 'false'])
.default('false')
.transform((value) => value === 'true'),
FEW_SHOT_EXAMPLES_COUNT: z.coerce.number().int().min(0).max(20).default(10),
// Reflection和Debate配置第三阶段
ENABLE_REFLECTION: z
.enum(['true', 'false'])
.default('false')
.transform((value) => value === 'true'),
MAX_REFLECTION_ROUNDS: z.coerce.number().int().min(1).max(5).default(2),
ENABLE_DEBATE: z
.enum(['true', 'false'])
.default('false')
.transform((value) => value === 'true'),
DEBATE_THRESHOLD: z.enum(['high', 'medium']).default('high'),
});
// 处理验证结果
@@ -74,4 +115,31 @@ export default {
jwtSecret: envParseResult.success ? envParseResult.data.JWT_SECRET : 'a-secure-secret-for-jwt',
giteaAdminToken: envParseResult.success ? envParseResult.data.GITEA_ADMIN_TOKEN : undefined,
},
review: {
engine: envParseResult.success ? envParseResult.data.REVIEW_ENGINE : 'legacy',
workdir: envParseResult.success ? envParseResult.data.REVIEW_WORKDIR : '/tmp/gitea-assistant',
modelPlanner: envParseResult.success ? envParseResult.data.REVIEW_MODEL_PLANNER : 'gpt-4o-mini',
modelSpecialist: envParseResult.success ? envParseResult.data.REVIEW_MODEL_SPECIALIST : 'gpt-4o-mini',
modelJudge: envParseResult.success ? envParseResult.data.REVIEW_MODEL_JUDGE : 'gpt-4o-mini',
maxParallelRuns: envParseResult.success ? envParseResult.data.REVIEW_MAX_PARALLEL_RUNS : 2,
maxFilesPerRun: envParseResult.success ? envParseResult.data.REVIEW_MAX_FILES_PER_RUN : 200,
maxFileContentChars: envParseResult.success ? envParseResult.data.REVIEW_MAX_FILE_CONTENT_CHARS : 40_000,
autoPublishMinConfidence: envParseResult.success
? envParseResult.data.REVIEW_AUTO_PUBLISH_MIN_CONFIDENCE
: 0.8,
enableHumanGate: envParseResult.success ? envParseResult.data.REVIEW_ENABLE_HUMAN_GATE : true,
allowedCommands: envParseResult.success
? envParseResult.data.REVIEW_ALLOWED_COMMANDS.split(',')
.map((item) => item.trim())
.filter(Boolean)
: defaultAllowedReviewCommands,
commandTimeoutMs: envParseResult.success ? envParseResult.data.REVIEW_COMMAND_TIMEOUT_MS : 10000,
qdrantUrl: envParseResult.success ? envParseResult.data.QDRANT_URL : undefined,
enableMemory: envParseResult.success ? envParseResult.data.ENABLE_MEMORY : false,
fewShotExamplesCount: envParseResult.success ? envParseResult.data.FEW_SHOT_EXAMPLES_COUNT : 10,
enableReflection: envParseResult.success ? envParseResult.data.ENABLE_REFLECTION : false,
maxReflectionRounds: envParseResult.success ? envParseResult.data.MAX_REFLECTION_ROUNDS : 2,
enableDebate: envParseResult.success ? envParseResult.data.ENABLE_DEBATE : false,
debateThreshold: envParseResult.success ? envParseResult.data.DEBATE_THRESHOLD : 'high',
},
};