mcp-codesentry
Version:
CodeSentry MCP - AI-powered code review assistant with 5 specialized review tools for security, best practices, and comprehensive code analysis
180 lines (169 loc) • 6.22 kB
JavaScript
/**
* Google Gemini API Client
* Handles interactions with Gemini for code reviews
*/
import { GoogleGenerativeAI } from '@google/generative-ai';
import { logger } from '../utils/logger.js';
export class GeminiClient {
client;
proModel;
flashModel;
config;
constructor(config) {
if (!config.apiKey) {
throw new Error('Gemini API key is required');
}
this.config = config;
this.client = new GoogleGenerativeAI(config.apiKey);
this.proModel = this.client.getGenerativeModel({ model: config.proModel });
this.flashModel = this.client.getGenerativeModel({ model: config.flashModel });
logger.info('Gemini client initialized');
}
async reviewPlan(params) {
logger.info(`Reviewing plan for task: ${params.taskId}`);
const prompt = this.buildPlanReviewPrompt(params);
try {
// Use Pro model for plan reviews (more complex reasoning)
const result = await this.proModel.generateContent({
contents: [{ role: 'user', parts: [{ text: prompt }] }],
generationConfig: {
temperature: 0.3,
maxOutputTokens: 8192,
responseMimeType: 'application/json'
}
});
const response = result.response;
const text = response.text();
return this.parseReviewResponse(text, 'plan', params.taskId);
}
catch (error) {
logger.error('Error calling Gemini API for plan review:', error);
throw error;
}
}
async reviewImplementation(params) {
logger.info(`Reviewing implementation for task: ${params.taskId}`);
const prompt = this.buildImplementationReviewPrompt(params);
try {
// Use Flash model for implementation reviews (faster, pattern matching)
const result = await this.flashModel.generateContent({
contents: [{ role: 'user', parts: [{ text: prompt }] }],
generationConfig: {
temperature: 0.2,
maxOutputTokens: 8192,
responseMimeType: 'application/json'
}
});
const response = result.response;
const text = response.text();
return this.parseReviewResponse(text, 'implementation', params.taskId);
}
catch (error) {
logger.error('Error calling Gemini API for implementation review:', error);
throw error;
}
}
buildPlanReviewPrompt(params) {
return `You are a senior software architect reviewing an implementation plan. Analyze the following plan and provide structured feedback.
Task ID: ${params.taskId}
Task Description: ${params.taskDescription}
Implementation Plan:
${params.implementationPlan}
Codebase Context:
${params.codebaseContext}
Please provide a JSON response with the following structure:
{
"approved": boolean,
"feedback": {
"summary": "Brief overall assessment",
"issues": ["List of critical issues or concerns"],
"suggestions": ["List of recommendations"],
"strengths": ["List of positive aspects"]
},
"metadata": {
"confidence": 0.0-1.0
}
}
Consider:
1. Architectural soundness
2. Security implications
3. Performance considerations
4. Maintainability
5. Alignment with task requirements
6. Best practices adherence`;
}
buildImplementationReviewPrompt(params) {
return `You are a senior software architect reviewing a completed implementation. Compare the implementation against the original plan and provide structured feedback.
Task ID: ${params.taskId}
Task Description: ${params.taskDescription}
Original Plan:
${params.originalPlan}
Implementation Summary:
${params.implementationSummary}
Current Codebase State:
${params.codebaseSnapshot}
Please provide a JSON response with the following structure:
{
"approved": boolean,
"feedback": {
"summary": "Brief overall assessment",
"issues": ["List of deviations or problems"],
"suggestions": ["List of improvements"],
"strengths": ["List of well-implemented aspects"]
},
"metadata": {
"confidence": 0.0-1.0
}
}
Consider:
1. Adherence to the original plan
2. Code quality and best practices
3. Test coverage
4. Documentation completeness
5. Security and performance
6. Any technical debt introduced`;
}
parseReviewResponse(responseText, reviewType, taskId) {
try {
const parsed = JSON.parse(responseText);
return {
approved: parsed.approved || false,
reviewType,
feedback: {
summary: parsed.feedback?.summary || 'No summary provided',
issues: parsed.feedback?.issues || [],
suggestions: parsed.feedback?.suggestions || [],
strengths: parsed.feedback?.strengths || []
},
metadata: {
taskId,
reviewedAt: new Date().toISOString(),
modelUsed: reviewType === 'plan' ? this.config.proModel : this.config.flashModel,
confidence: parsed.metadata?.confidence || 0.5
}
};
}
catch (error) {
logger.error('Error parsing Gemini response:', error);
logger.error('Raw response:', responseText);
// Return a default response on parse error
return {
approved: false,
reviewType,
feedback: {
summary: 'Error parsing review response',
issues: ['Failed to parse AI response'],
suggestions: ['Please retry the review'],
strengths: []
},
metadata: {
taskId,
reviewedAt: new Date().toISOString(),
modelUsed: reviewType === 'plan' ? this.config.proModel : this.config.flashModel,
confidence: 0
}
};
}
}
}
//# sourceMappingURL=client.js.map