Skip to content

Commit 2900c9e

Browse files
Add Google support (#73)
1 parent 3c62cdd commit 2900c9e

File tree

7 files changed

+74
-117
lines changed

7 files changed

+74
-117
lines changed

.github/workflows/aireview.yaml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,23 @@ jobs:
1313
uses: AleksandrFurmenkovOfficial/ai-code-review@main
1414
with:
1515
token: ${{ secrets.GITHUB_TOKEN }}
16+
1617
# AI Provider Configuration
17-
ai_provider: 'openai' # Can be 'openai', 'anthropic', ('google', or 'deepseek') soon
18+
ai_provider: 'google' # Can be 'openai', 'anthropic', 'google', ('deepseek' soon)
1819

1920
# Anthropic Configuration (if using Anthropic)
2021
# anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
21-
# anthropic_model: 'claude-3-7-sonnet-20250219' # Optional
22+
# anthropic_model: 'claude-3-7-sonnet-20250219' # Optional, defaults to 'claude-3-7-sonnet-latest'
2223

2324
# OpenAI Configuration (if using OpenAI)
24-
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
25+
# openai_api_key: ${{ secrets.OPENAI_API_KEY }}
2526
# openai_model: 'gpt-4o' # Optional, defaults to 'gpt-4o'
2627

2728
# Google Configuration (if using Google)
28-
# google_api_key: ${{ secrets.GOOGLE_API_KEY }}
29-
# google_model: 'gemini-2.0-flash-thinking-exp-01-21' # Optional
29+
google_api_key: ${{ secrets.GOOGLE_API_KEY }}
30+
google_model: 'gemini-2.0-flash' # Optional, defaults to 'gemini-2.0-flash'
3031

31-
# Deepseek Configuration (if using Deepseek)
32+
# Soon - Deepseek Configuration (if using Deepseek)
3233
# deepseek_api_key: ${{ secrets.DEEPSEEK_API_KEY }}
3334
# deepseek_model: 'deepseek-reasoner' # Optional
3435

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
## Description
55

6-
Perform code review using various AI models (from OpenAI, Anthropic, and soon Google, Deepseek) to analyze and provide feedback on your code. This GitHub Action helps improve the code quality by automatically reviewing pull requests, focusing on specified file extensions, and excluding specific paths.
6+
Perform code review using various AI models from OpenAI, Anthropic, Google, Deepseek(soon) to analyze and provide feedback on your code. This GitHub Action helps improve the code quality by automatically reviewing pull requests, focusing on specified file extensions, and excluding specific paths.
77

88
## Inputs
99

@@ -15,7 +15,7 @@ Perform code review using various AI models (from OpenAI, Anthropic, and soon Go
1515

1616
***pr_number*** - Required. The number of the pull request that needs to be reviewed.
1717

18-
***ai_provider*** - Required. The AI provider to use (openai, anthropic, and soon google, deepseek). Default is 'openai'.
18+
***ai_provider*** - Required. The AI provider to use { openai, anthropic, google, deepseek(soon)}. Default is 'openai'.
1919

2020

2121
***openai_api_key*** - Required if using OpenAI provider. This key is necessary to access OpenAI's API for code review purposes.
@@ -30,7 +30,7 @@ Perform code review using various AI models (from OpenAI, Anthropic, and soon Go
3030

3131
***google_api_key*** - Required if using Google provider. This key is necessary to access Google's API for code review purposes.
3232

33-
***google_model*** - Optional. The Google model name (e.g., gemini-2.0-flash-thinking-exp-01-21). Default is 'gemini-2.0-flash-thinking-exp-01-21'.
33+
***google_model*** - Optional. The Google model name (e.g., gemini-2.0-flash). Default is 'gemini-2.0-flash'.
3434

3535

3636
***deepseek_api_key*** - Required if using Deepseek provider. This key is necessary to access Deepseek's API for code review purposes.
@@ -66,7 +66,7 @@ jobs:
6666
runs-on: ubuntu-latest
6767
steps:
6868
- name: AI Code Review
69-
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.6
69+
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.7
7070
with:
7171
token: ${{ secrets.GITHUB_TOKEN }}
7272
owner: ${{ github.repository_owner }}
@@ -92,7 +92,7 @@ jobs:
9292
runs-on: ubuntu-latest
9393
steps:
9494
- name: AI Code Review
95-
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.6
95+
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.7
9696
with:
9797
token: ${{ secrets.GITHUB_TOKEN }}
9898
owner: ${{ github.repository_owner }}
@@ -118,7 +118,7 @@ jobs:
118118
runs-on: ubuntu-latest
119119
steps:
120120
- name: AI Code Review
121-
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.6
121+
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.7
122122
with:
123123
token: ${{ secrets.GITHUB_TOKEN }}
124124
owner: ${{ github.repository_owner }}
@@ -135,7 +135,7 @@ jobs:
135135
fail_action_if_review_failed: 'true'
136136
```
137137
138-
### Google Example (soon or suggest your PR to include)
138+
### Google Example
139139
140140
```yaml
141141
name: AI Code Review with Google
@@ -149,7 +149,7 @@ jobs:
149149
runs-on: ubuntu-latest
150150
steps:
151151
- name: AI Code Review
152-
uses: AleksandrFurmenkovOfficial/ai-code-review@main
152+
uses: AleksandrFurmenkovOfficial/ai-code-review@v0.7
153153
with:
154154
token: ${{ secrets.GITHUB_TOKEN }}
155155
owner: ${{ github.repository_owner }}
@@ -158,7 +158,7 @@ jobs:
158158

159159
ai_provider: 'google'
160160
google_api_key: ${{ secrets.GOOGLE_API_KEY }}
161-
google_model: 'gemini-2.0-flash-thinking-exp-01-21'
161+
google_model: 'gemini-2.0-flash'
162162
```
163163
164164
### Deepseek Example (soon or suggest your PR to include)

action.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
name: 'AI Code Review'
2-
description: 'Perform code review using various AI models (OpenAI, Anthropic, and soon Google, Deepseek)'
2+
description: 'Perform code review using various AI models from OpenAI, Anthropic, Google and soon Deepseek'
33

44
inputs:
55
token:
66
description: 'GitHub token'
77
required: true
88
ai_provider:
9-
description: 'AI provider to use (openai, anthropic, and soon google, deepseek)'
9+
description: 'AI provider to use (openai, anthropic, google and soon deepseek)'
1010
required: true
1111
default: 'openai'
1212
openai_api_key:
@@ -27,9 +27,9 @@ inputs:
2727
description: 'Google AI API key (required if using Google provider)'
2828
required: false
2929
google_model:
30-
description: 'Google model name (e.g., gemini-2.0-flash-thinking-exp-01-21)'
30+
description: 'Google model name (e.g., gemini-2.0-flash)'
3131
required: false
32-
default: 'gemini-2.0-flash-thinking-exp-01-21'
32+
default: 'gemini-2.0-flash'
3333
deepseek_api_key:
3434
description: 'Deepseek API key (required if using Deepseek provider)'
3535
required: false

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ai-code-review",
3-
"version": "1.1.0",
3+
"version": "0.7.0",
44
"description": "AI Code Review is a GitHub Action that integrates various AI models (OpenAI, Google, Anthropic, Deepseek) into your code review process, providing automated feedback on pull requests. Improve your code quality and streamline your development workflow with this powerful and customizable AI-driven code review tool.",
55
"main": "index.js",
66
"scripts": {

src/google-agent.js

Lines changed: 4 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,8 @@
1-
const { warning, info } = require("@actions/core");
2-
const { GoogleGenerativeAI } = require("@google/generative-ai");
3-
const BaseAIAgent = require("./base-ai-agent");
1+
const OpenAIAgent = require("./openai-agent");
42

5-
class GoogleAgent extends BaseAIAgent {
6-
constructor(apiKey, fileContentGetter, fileCommentator, model, failAction = false) {
7-
super(apiKey, fileContentGetter, fileCommentator, model, failAction);
8-
this.genAI = new GoogleGenerativeAI(apiKey);
9-
}
10-
11-
async initialize() {
12-
try {
13-
this.model = this.genAI.getGenerativeModel({
14-
model: this.model,
15-
systemInstruction: `You are an expert AI code reviewer responsible for reviewing GitHub PRs.
16-
Review the user's changes for typos, logical errors, and security issues.
17-
Use the provided tools to add specific, actionable comments.
18-
Avoid repeating the same issue multiple times.
19-
Comment only when you are confident! Do not report minor issues.
20-
Use 'getFileContent' when you need more context.
21-
Provide results only via the provided functions.`
22-
});
23-
return true;
24-
} catch (error) {
25-
this.handleError(error, 'Error initializing Google AI model');
26-
return false;
27-
}
28-
}
29-
30-
async doReview(changedFiles) {
31-
let reviewSummary = '';
32-
const simpleChangedFiles = changedFiles.map(file => ({
33-
filename: file.filename,
34-
status: file.status,
35-
additions: file.additions,
36-
deletions: file.deletions,
37-
changes: file.changes,
38-
patch: file.patch
39-
}));
40-
41-
try {
42-
await this.initialize();
43-
44-
const maxRetries = 3;
45-
const initialBackoff = 1000;
46-
47-
for (let retries = 0; retries < maxRetries; retries++) {
48-
try {
49-
reviewSummary = await this.processReview(simpleChangedFiles);
50-
break;
51-
} catch (error) {
52-
if (retries >= maxRetries - 1) {
53-
this.handleError(error, 'Max retries reached for code review');
54-
}
55-
56-
const backoff = initialBackoff * Math.pow(2, retries) + Math.random() * 1000;
57-
warning(`Retry ${retries + 1}/${maxRetries}: ${error.message}. Retrying in ${Math.round(backoff)}ms`);
58-
await new Promise(resolve => setTimeout(resolve, backoff));
59-
}
60-
}
61-
} catch (error) {
62-
this.handleError(error, 'Error in code review process', false);
63-
}
64-
65-
return reviewSummary;
66-
}
67-
68-
async processReview(changedFiles) {
69-
warning("Google AI provider is not fully implemented yet. This is a placeholder implementation.");
70-
info("Processing changed files with Google AI...");
71-
72-
let reviewedFiles = 0;
73-
let commentsMade = 0;
74-
75-
return `Code review with Google AI completed. This is currently a placeholder implementation. Full support for Google AI will be added in future versions.`;
3+
class GoogleAgent extends OpenAIAgent {
4+
constructor(apiKey, fileContentGetter, fileCommentator, model) {
5+
super(apiKey, fileContentGetter, fileCommentator, model, "https://generativelanguage.googleapis.com/v1beta/openai/");
766
}
777
}
788

src/openai-agent.js

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1+
const core = require("@actions/core");
12
const { OpenAI } = require('openai');
23
const BaseAIAgent = require("./base-ai-agent");
34

4-
const c_max_completion_tokens = 8192;
5-
65
class OpenAIAgent extends BaseAIAgent {
7-
constructor(apiKey, fileContentGetter, fileCommentator, model) {
6+
constructor(apiKey, fileContentGetter, fileCommentator, model, baseURL = null) {
87
super(apiKey, fileContentGetter, fileCommentator, model);
9-
this.openai = new OpenAI({ apiKey });
8+
9+
if (baseURL == null || baseURL === undefined || baseURL.trim() === '' ) {
10+
core.info("Using default OpenAI API URL");
11+
this.openai = new OpenAI({ apiKey});
12+
}
13+
else {
14+
core.info(`Using custom baseUrl: ${baseURL}`);
15+
this.openai = new OpenAI({ apiKey : apiKey, baseURL : baseURL});
16+
}
17+
1018
this.tools = [
1119
{
1220
type: "function",
@@ -128,14 +136,23 @@ class OpenAIAgent extends BaseAIAgent {
128136
}
129137

130138
// Proceed to the next API call
131-
const nextResponse = await this.openai.chat.completions.create({
132-
model: this.model,
133-
messages: [{ role: 'system', content: this.getSystemPrompt() }, ...reviewState.messageHistory],
134-
tools: this.tools,
135-
max_completion_tokens: c_max_completion_tokens
136-
});
137-
const nextMessage = nextResponse.choices[0].message;
138-
return await this.handleMessageResponse(nextMessage, reviewState);
139+
try {
140+
core.info(`Sending follow-up request to OpenAI with model: ${this.model}`);
141+
const nextResponse = await this.openai.chat.completions.create({
142+
model: this.model,
143+
messages: [{ role: 'system', content: this.getSystemPrompt() }, ...reviewState.messageHistory],
144+
tools: this.tools
145+
});
146+
const nextMessage = nextResponse.choices[0].message;
147+
return await this.handleMessageResponse(nextMessage, reviewState);
148+
} catch (error) {
149+
core.error(`OpenAI API error in follow-up request: ${error.message}`);
150+
if (error.response) {
151+
core.error(`Status: ${error.response.status}`);
152+
core.error(`Data: ${JSON.stringify(error.response.data)}`);
153+
}
154+
throw error;
155+
}
139156
} else {
140157
if (message.content && !reviewState.summary) {
141158
reviewState.summary = message.content;
@@ -173,15 +190,24 @@ class OpenAIAgent extends BaseAIAgent {
173190

174191
reviewState.messageHistory.push(initialUserMessage);
175192

176-
const initialResponse = await this.openai.chat.completions.create({
177-
model: this.model,
178-
messages: [{ role: 'system', content: this.getSystemPrompt() }, ...reviewState.messageHistory],
179-
tools: this.tools,
180-
max_completion_tokens: c_max_completion_tokens
181-
});
182-
const initialMessage = initialResponse.choices[0].message;
183-
reviewSummary = await this.handleMessageResponse(initialMessage, reviewState);
184-
return reviewSummary;
193+
try {
194+
core.info(`Sending initial request to OpenAI with model: ${this.model}`);
195+
const initialResponse = await this.openai.chat.completions.create({
196+
model: this.model,
197+
messages: [{ role: 'system', content: this.getSystemPrompt() }, ...reviewState.messageHistory],
198+
tools: this.tools
199+
});
200+
const initialMessage = initialResponse.choices[0].message;
201+
reviewSummary = await this.handleMessageResponse(initialMessage, reviewState);
202+
return reviewSummary;
203+
} catch (error) {
204+
core.error(`OpenAI API error: ${error.message}`);
205+
if (error.response) {
206+
core.error(`Status: ${error.response.status}`);
207+
core.error(`Data: ${JSON.stringify(error.response.data)}`);
208+
}
209+
throw error;
210+
}
185211
}
186212

187213
async getFileContent(args) {

0 commit comments

Comments
 (0)