@ztimson/ai-agents 0.0.2 → 0.0.4
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/LICENSE +11 -11
- package/README.md +84 -81
- package/package.json +3 -2
- package/src/refine.mjs +110 -0
- package/src/review.mjs +113 -96
package/LICENSE
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Copyright (c) 2023 Zakary Timson
|
|
2
|
-
|
|
3
|
-
All Rights Reserved.
|
|
4
|
-
|
|
5
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
6
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
7
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
8
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
9
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
10
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
11
|
-
THE SOFTWARE.
|
|
1
|
+
Copyright (c) 2023 Zakary Timson
|
|
2
|
+
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
6
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
7
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
8
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
9
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
10
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
11
|
+
THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,81 +1,84 @@
|
|
|
1
|
-
<!-- Header -->
|
|
2
|
-
<div id="top" align="center">
|
|
3
|
-
<br />
|
|
4
|
-
|
|
5
|
-
<!-- Logo -->
|
|
6
|
-
<img src="https://git.zakscode.com/repo-avatars/
|
|
7
|
-
|
|
8
|
-
<!-- Title -->
|
|
9
|
-
### AI Agents
|
|
10
|
-
|
|
11
|
-
<!-- Description -->
|
|
12
|
-
Automated AI-powered agents for automated reviews and code assistance
|
|
13
|
-
|
|
14
|
-
<!-- Repo badges -->
|
|
15
|
-
[](https://git.zakscode.com/ztimson/ai-agents/tags)
|
|
16
|
-
[](https://git.zakscode.com/ztimson/ai-agents/pulls)
|
|
17
|
-
[](https://git.zakscode.com/ztimson/ai-agents/issues)
|
|
18
|
-
|
|
19
|
-
<!-- Links -->
|
|
20
|
-
---
|
|
21
|
-
<div>
|
|
22
|
-
<a href="https://git.zakscode.com/ztimson/ai-agents/releases" target="_blank">Release Notes</a>
|
|
23
|
-
• <a href="https://git.zakscode.com/ztimson/ai-agents/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
|
|
24
|
-
• <a href="https://git.zakscode.com/ztimson/ai-agents/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
## Table of Contents
|
|
31
|
-
- [AI Agents](#top)
|
|
32
|
-
- [About](#about)
|
|
33
|
-
- [Built With](#built-with)
|
|
34
|
-
- [Setup](#setup)
|
|
35
|
-
- [Production](#production)
|
|
36
|
-
- [License](#license)
|
|
37
|
-
|
|
38
|
-
## About
|
|
39
|
-
|
|
40
|
-
Automated code agents that uses AI to analyze git diffs and provide inline comments on pull requests. Supports Anthropic, OpenAI, and Ollama models with tool-based reviewing for precise feedback.
|
|
41
|
-
|
|
42
|
-
### Built With
|
|
43
|
-
[](https://docker.com/)
|
|
44
|
-
[](https://javascript.com/)
|
|
45
|
-
[](https://nodejs.org/)
|
|
46
|
-
|
|
47
|
-
## Setup
|
|
48
|
-
|
|
49
|
-
<details>
|
|
50
|
-
<summary>
|
|
51
|
-
<h3 id="production" style="display: inline">
|
|
52
|
-
Production
|
|
53
|
-
</h3>
|
|
54
|
-
</summary>
|
|
55
|
-
|
|
56
|
-
####
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
####
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
1
|
+
<!-- Header -->
|
|
2
|
+
<div id="top" align="center">
|
|
3
|
+
<br />
|
|
4
|
+
|
|
5
|
+
<!-- Logo -->
|
|
6
|
+
<img src="https://git.zakscode.com/repo-avatars/309c233243bcd1c1e9b3f359ec3f59769bb01b655e8ed7b32587781be4c8b21c" alt="Logo" width="200" height="200">
|
|
7
|
+
|
|
8
|
+
<!-- Title -->
|
|
9
|
+
### AI Agents
|
|
10
|
+
|
|
11
|
+
<!-- Description -->
|
|
12
|
+
Automated AI-powered agents for automated reviews and code assistance
|
|
13
|
+
|
|
14
|
+
<!-- Repo badges -->
|
|
15
|
+
[](https://git.zakscode.com/ztimson/ai-agents/tags)
|
|
16
|
+
[](https://git.zakscode.com/ztimson/ai-agents/pulls)
|
|
17
|
+
[](https://git.zakscode.com/ztimson/ai-agents/issues)
|
|
18
|
+
|
|
19
|
+
<!-- Links -->
|
|
20
|
+
---
|
|
21
|
+
<div>
|
|
22
|
+
<a href="https://git.zakscode.com/ztimson/ai-agents/releases" target="_blank">Release Notes</a>
|
|
23
|
+
• <a href="https://git.zakscode.com/ztimson/ai-agents/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
|
|
24
|
+
• <a href="https://git.zakscode.com/ztimson/ai-agents/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## Table of Contents
|
|
31
|
+
- [AI Agents](#top)
|
|
32
|
+
- [About](#about)
|
|
33
|
+
- [Built With](#built-with)
|
|
34
|
+
- [Setup](#setup)
|
|
35
|
+
- [Production](#production)
|
|
36
|
+
- [License](#license)
|
|
37
|
+
|
|
38
|
+
## About
|
|
39
|
+
|
|
40
|
+
Automated code agents that uses AI to analyze git diffs and provide inline comments on pull requests. Supports Anthropic, OpenAI, and Ollama models with tool-based reviewing for precise feedback.
|
|
41
|
+
|
|
42
|
+
### Built With
|
|
43
|
+
[](https://docker.com/)
|
|
44
|
+
[](https://javascript.com/)
|
|
45
|
+
[](https://nodejs.org/)
|
|
46
|
+
|
|
47
|
+
## Setup
|
|
48
|
+
|
|
49
|
+
<details>
|
|
50
|
+
<summary>
|
|
51
|
+
<h3 id="production" style="display: inline">
|
|
52
|
+
Production
|
|
53
|
+
</h3>
|
|
54
|
+
</summary>
|
|
55
|
+
|
|
56
|
+
#### Prerequisites
|
|
57
|
+
- [Node.js](https://nodejs.org/en/download)
|
|
58
|
+
|
|
59
|
+
#### Instructions
|
|
60
|
+
1. Run using npx: `npx -y @ztimson/ai-agents@latest review`
|
|
61
|
+
|
|
62
|
+
</details>
|
|
63
|
+
|
|
64
|
+
<details>
|
|
65
|
+
<summary>
|
|
66
|
+
<h3 id="development" style="display: inline">
|
|
67
|
+
Development
|
|
68
|
+
</h3>
|
|
69
|
+
</summary>
|
|
70
|
+
|
|
71
|
+
#### Prerequisites
|
|
72
|
+
- [Node.js](https://nodejs.org/en/download)
|
|
73
|
+
|
|
74
|
+
#### Instructions
|
|
75
|
+
1. Install the dependencies: `npm i`
|
|
76
|
+
2. Build library: `npm run review`
|
|
77
|
+
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
Copyright © 2025 Zakary Timson | All Rights Reserved | Available under MIT Licensing
|
|
83
|
+
|
|
84
|
+
See the [license](./LICENSE) for more information.
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ztimson/ai-agents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "AI agents",
|
|
5
5
|
"keywords": ["ai", "review"],
|
|
6
6
|
"author": "ztimson",
|
|
7
7
|
"license": "ISC",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"bin": {
|
|
10
|
-
"
|
|
10
|
+
"refine": "./src/refine.mjs",
|
|
11
|
+
"review": "./src/review.mjs"
|
|
11
12
|
},
|
|
12
13
|
"dependencies": {
|
|
13
14
|
"@ztimson/ai-utils": "^0.2.4",
|
package/src/refine.mjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {Ai} from '@ztimson/ai-utils';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as dotenv from 'dotenv';
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
|
|
9
|
+
dotenv.config({quiet: true});
|
|
10
|
+
dotenv.config({path: '.env.local', override: true, quiet: true});
|
|
11
|
+
|
|
12
|
+
(async () => {
|
|
13
|
+
let p = process.argv[process.argv.length - 1];
|
|
14
|
+
if(p === 'refine' || p.endsWith('refine.mjs')) p = null;
|
|
15
|
+
if(!/^(\/|[A-Z]:)/m.test(p)) p = path.join(process.cwd(), p);
|
|
16
|
+
|
|
17
|
+
if(!p || !fs.existsSync(p)) throw new Error('Please provide a template');
|
|
18
|
+
|
|
19
|
+
const git = process.env['GIT_HOST'],
|
|
20
|
+
owner = process.env['GIT_OWNER'],
|
|
21
|
+
repo = process.env['GIT_REPO'],
|
|
22
|
+
auth = process.env['GIT_TOKEN'],
|
|
23
|
+
ticket = process.env['TICKET'],
|
|
24
|
+
host = process.env['AI_HOST'],
|
|
25
|
+
model = process.env['AI_MODEL'],
|
|
26
|
+
token = process.env['AI_TOKEN'];
|
|
27
|
+
|
|
28
|
+
console.log(`Processing issue #${ticket}`);
|
|
29
|
+
|
|
30
|
+
// Fetch issue
|
|
31
|
+
const issueRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, {
|
|
32
|
+
headers: {'Authorization': `token ${auth}`}
|
|
33
|
+
});
|
|
34
|
+
if(!issueRes.ok) throw new Error(`${issueRes.status} ${await issueRes.text()}`);
|
|
35
|
+
const issueData = await issueRes.json();
|
|
36
|
+
if(!issueData.labels?.some(l => l.name === 'Review/AI')) {
|
|
37
|
+
console.log('Skipping');
|
|
38
|
+
return process.exit();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let readme = '', readmeP = path.join(process.cwd(), 'README.md');
|
|
42
|
+
if(fs.existsSync(readmeP)) readme = fs.readFileSync(readmeP, 'utf-8');
|
|
43
|
+
const template = fs.readFileSync(p, 'utf-8');
|
|
44
|
+
|
|
45
|
+
let options = {ollama: {model, host}};
|
|
46
|
+
if(host === 'anthropic') options = {anthropic: {model, token}};
|
|
47
|
+
else if(host === 'openai') options = {openAi: {model, token}};
|
|
48
|
+
const ai = new Ai({
|
|
49
|
+
...options,
|
|
50
|
+
model: [host, model],
|
|
51
|
+
path: process.env['path'] || os.tmpdir(),
|
|
52
|
+
system: `You are a ticket formatter. Transform raw issue descriptions into structured tickets.
|
|
53
|
+
|
|
54
|
+
**CRITICAL RULES:**
|
|
55
|
+
1. Identify the ticket type (Bug, DevOps, Enhancement, Refactor, Security)
|
|
56
|
+
2. Output MUST only contain the new ticket information in markdown, no extra fluff
|
|
57
|
+
3. Follow the template structure EXACTLY:
|
|
58
|
+
- Title format: [Module] - [Verb] [noun]
|
|
59
|
+
Example: Storage - Fix file uploads
|
|
60
|
+
- Fill in the identified ticket type
|
|
61
|
+
- Write a clear description
|
|
62
|
+
- For bugs: fill Steps to Reproduce with numbered list
|
|
63
|
+
- For enhancements/refactors: REMOVE the Steps to Reproduce section entirely
|
|
64
|
+
- Acceptance Criteria: convert requirements into checkboxes (- [ ])
|
|
65
|
+
- Weight scoring (0-5 each):
|
|
66
|
+
* Size: Number of modules, layers & files affected by change
|
|
67
|
+
* Complexity: Technical difficulty to implement
|
|
68
|
+
* Unknowns: Research/uncertainty in work estimation
|
|
69
|
+
* Calculate Total as sum of the three
|
|
70
|
+
- Remove sections that are not applicable based on ticket type
|
|
71
|
+
- Use proper markdown headers (##)
|
|
72
|
+
|
|
73
|
+
**README:**
|
|
74
|
+
\`\`\`markdown
|
|
75
|
+
${readme.trim() || 'No README available'}
|
|
76
|
+
\`\`\`
|
|
77
|
+
|
|
78
|
+
**TEMPLATE:**
|
|
79
|
+
\`\`\`markdown
|
|
80
|
+
${template.trim()}
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
Output ONLY the formatted ticket, no explanation.`
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const messages = await ai.language.ask(`Title: ${issueData.title}\n\nDescription:\n${issueData.body || 'No description provided'}`).catch(() => []);
|
|
87
|
+
const content = messages?.pop()?.content;
|
|
88
|
+
if(!content) {
|
|
89
|
+
console.log('Invalid response from AI');
|
|
90
|
+
return process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const title = /^# (.+)$/m.exec(content)?.[1] || issueData.title;
|
|
93
|
+
const typeMatch = /^## Type:\s*(.+)$/m.exec(content);
|
|
94
|
+
const type = typeMatch?.[1]?.split('/')[0]?.trim() || 'Unassigned';
|
|
95
|
+
const body = content.replace(/^# .+$/m, '').replace(/^## Type:.+$/m, '').trim();
|
|
96
|
+
const updateRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, {
|
|
97
|
+
method: 'PATCH',
|
|
98
|
+
headers: {
|
|
99
|
+
'Authorization': `token ${auth}`,
|
|
100
|
+
'Content-Type': 'application/json'
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
title,
|
|
104
|
+
body,
|
|
105
|
+
labels: type?.length ? [`Kind/${type[0].toUpperCase() + type.slice(1).toLowerCase()}`] : []
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
if(!updateRes.ok) throw new Error(`${updateRes.status} ${await updateRes.text()}`);
|
|
109
|
+
console.log(body);
|
|
110
|
+
})();
|
package/src/review.mjs
CHANGED
|
@@ -1,96 +1,113 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import {Ai} from '@ztimson/ai-utils';
|
|
4
|
-
import {$} from '@ztimson/node-utils';
|
|
5
|
-
import * as os from 'node:os';
|
|
6
|
-
import * as path from 'node:path';
|
|
7
|
-
import * as fs from 'node:fs';
|
|
8
|
-
import * as dotenv from 'dotenv';
|
|
9
|
-
|
|
10
|
-
dotenv.config({quiet: true, debug: false});
|
|
11
|
-
dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
|
|
12
|
-
|
|
13
|
-
(async () => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {Ai} from '@ztimson/ai-utils';
|
|
4
|
+
import {$} from '@ztimson/node-utils';
|
|
5
|
+
import * as os from 'node:os';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as dotenv from 'dotenv';
|
|
9
|
+
|
|
10
|
+
dotenv.config({quiet: true, debug: false});
|
|
11
|
+
dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
|
|
12
|
+
|
|
13
|
+
(async () => {
|
|
14
|
+
let p = process.argv[process.argv.length - 1];
|
|
15
|
+
if(p === 'review' || p.endsWith('review.mjs')) p = null;
|
|
16
|
+
|
|
17
|
+
const root = p || process.cwd(),
|
|
18
|
+
git = process.env['GIT_HOST'],
|
|
19
|
+
owner = process.env['GIT_OWNER'],
|
|
20
|
+
repo = process.env['GIT_REPO'],
|
|
21
|
+
auth = process.env['GIT_TOKEN'],
|
|
22
|
+
pr = process.env['PULL_REQUEST'],
|
|
23
|
+
host = process.env['AI_HOST'],
|
|
24
|
+
model = process.env['AI_MODEL'],
|
|
25
|
+
token = process.env['AI_TOKEN'];
|
|
26
|
+
|
|
27
|
+
console.log(`Reviewing: ${root}\n`);
|
|
28
|
+
const branch = process.env['GIT_BRANCH'] || await $`cd ${root} && git symbolic-ref refs/remotes/origin/HEAD`;
|
|
29
|
+
const comments = [];
|
|
30
|
+
const commit = await $`cd ${root} && git log -1 --pretty=format:%H`;
|
|
31
|
+
const gitDiff = await $`cd ${root} && git diff ${branch}`;
|
|
32
|
+
|
|
33
|
+
if(!gitDiff) {
|
|
34
|
+
console.warn('No diff found');
|
|
35
|
+
return process.exit();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let existingComments = '';
|
|
39
|
+
if(git && pr) {
|
|
40
|
+
const res = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}/reviews`, {
|
|
41
|
+
headers: {'Authorization': `token ${auth}`}
|
|
42
|
+
});
|
|
43
|
+
if(res.ok) {
|
|
44
|
+
const reviews = await res.json();
|
|
45
|
+
const allComments = reviews.flatMap(r => r.comments || []);
|
|
46
|
+
if(allComments.length) {
|
|
47
|
+
existingComments = '\n\nExisting review comments (DO NOT repeat these):\n' +
|
|
48
|
+
allComments.map(c => `- ${c.path}:${c.line || c.position}: ${c.body}`).join('\n');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let options = {ollama: {model, host}};
|
|
54
|
+
if(host === 'anthropic') options = {anthropic: {model, token}};
|
|
55
|
+
else if(host === 'openai') options = {openAi: {model, token}};
|
|
56
|
+
const ai = new Ai({
|
|
57
|
+
...options,
|
|
58
|
+
model: [host, model],
|
|
59
|
+
path: process.env['path'] || os.tmpdir(),
|
|
60
|
+
system: `You are a code reviewer. Analyze the git diff and use the \`recommend\` tool for EACH issue you find. You must call \`recommend\` exactly once for every bug or improvement opportunity directly related to changes. Ignore formatting recommendations. After making all recommendations, provide some concluding remarks about the overall state of the changes.${existingComments}`,
|
|
61
|
+
tools: [{
|
|
62
|
+
name: 'read_file',
|
|
63
|
+
description: 'Read contents of a file',
|
|
64
|
+
args: {
|
|
65
|
+
path: {type: 'string', description: 'Path to file relative to project root'}
|
|
66
|
+
},
|
|
67
|
+
fn: (args) => fs.readFileSync(path.join(root, args.path), 'utf-8')
|
|
68
|
+
}, {
|
|
69
|
+
name: 'get_diff',
|
|
70
|
+
description: 'Check a file for differences using git',
|
|
71
|
+
args: {
|
|
72
|
+
path: {type: 'string', description: 'Path to file relative to project root'}
|
|
73
|
+
},
|
|
74
|
+
fn: async (args) => await $`git diff HEAD^..HEAD -- ${path.join(root, args.path)}`
|
|
75
|
+
}, {
|
|
76
|
+
name: 'recommend',
|
|
77
|
+
description: 'REQUIRED: Call this once for every bug, improvement, or concern identified in the review.',
|
|
78
|
+
args: {
|
|
79
|
+
file: {type: 'string', description: 'File path'},
|
|
80
|
+
line: {type: 'number', description: 'Line number in new file'},
|
|
81
|
+
comment: {type: 'string', description: 'Review comment explaining the issue'}
|
|
82
|
+
},
|
|
83
|
+
fn: (args) => {
|
|
84
|
+
comments.push({
|
|
85
|
+
path: args.file,
|
|
86
|
+
new_position: args.line,
|
|
87
|
+
body: args.comment,
|
|
88
|
+
});
|
|
89
|
+
return 'Comment recorded, continue reviewing';
|
|
90
|
+
}
|
|
91
|
+
}]
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const messages = await ai.language.ask(gitDiff);
|
|
95
|
+
const summary = messages.pop().content;
|
|
96
|
+
if(git) {
|
|
97
|
+
const res = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}/reviews`, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
'Authorization': `token ${auth}`,
|
|
101
|
+
'Content-Type': 'application/json'
|
|
102
|
+
},
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
body: summary,
|
|
105
|
+
commit_id: commit,
|
|
106
|
+
event: 'COMMENT',
|
|
107
|
+
comments,
|
|
108
|
+
})
|
|
109
|
+
});
|
|
110
|
+
if(!res.ok) throw new Error(`${res.status} ${await res.text()}`);
|
|
111
|
+
}
|
|
112
|
+
console.log(comments.map(c => `${c.path}${c.new_position ? `:${c.new_position}` : ''}\n${c.body}`).join('\n\n') + '\n\n' + summary);
|
|
113
|
+
})();
|