@ztimson/ai-agents 0.0.1 → 0.0.3
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/package.json +2 -2
- package/src/review.mjs +98 -94
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ztimson/ai-agents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
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
|
+
"review": "./src/review.mjs"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@ztimson/ai-utils": "^0.2.4",
|
package/src/review.mjs
CHANGED
|
@@ -1,94 +1,98 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
|
|
8
|
-
dotenv
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
})
|
|
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
|
+
let options = {ollama: {model, host}};
|
|
34
|
+
if(host === 'anthropic') options = {anthropic: {model, token}};
|
|
35
|
+
else if(host === 'openai') options = {openAi: {model, token}};
|
|
36
|
+
const ai = new Ai({
|
|
37
|
+
...options,
|
|
38
|
+
model: [host, model],
|
|
39
|
+
path: process.env['path'] || os.tmpdir(),
|
|
40
|
+
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. After making all recommendations, provide a brief bullet point summary in markdown.`,
|
|
41
|
+
tools: [{
|
|
42
|
+
name: 'read_file',
|
|
43
|
+
description: 'Read contents of a file',
|
|
44
|
+
args: {
|
|
45
|
+
path: {type: 'string', description: 'Path to file relative to project root'}
|
|
46
|
+
},
|
|
47
|
+
fn: (args) => fs.readFileSync(path.join(root, args.path), 'utf-8')
|
|
48
|
+
}, {
|
|
49
|
+
name: 'get_diff',
|
|
50
|
+
description: 'Check a file for differences using git',
|
|
51
|
+
args: {
|
|
52
|
+
path: {type: 'string', description: 'Path to file relative to project root'}
|
|
53
|
+
},
|
|
54
|
+
fn: async (args) => await $`git diff HEAD^..HEAD -- ${path.join(root, args.path)}`
|
|
55
|
+
}, {
|
|
56
|
+
name: 'recommend',
|
|
57
|
+
description: 'REQUIRED: Call this once for every bug, improvement, or concern identified in the review.',
|
|
58
|
+
args: {
|
|
59
|
+
file: {type: 'string', description: 'File path'},
|
|
60
|
+
line: {type: 'number', description: 'Line number in new file'},
|
|
61
|
+
comment: {type: 'string', description: 'Review comment explaining the issue'}
|
|
62
|
+
},
|
|
63
|
+
fn: (args) => {
|
|
64
|
+
comments.push({
|
|
65
|
+
path: args.file,
|
|
66
|
+
new_position: args.line,
|
|
67
|
+
body: args.comment,
|
|
68
|
+
});
|
|
69
|
+
return 'Comment recorded, continue reviewing';
|
|
70
|
+
}
|
|
71
|
+
}]
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if(!gitDiff) {
|
|
75
|
+
console.warn('No diff found');
|
|
76
|
+
return process.exit();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const messages = await ai.language.ask(gitDiff);
|
|
80
|
+
const summary = messages.pop().content;
|
|
81
|
+
if(git) {
|
|
82
|
+
const res = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}/reviews`, {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
headers: {
|
|
85
|
+
'Authorization': `token ${auth}`,
|
|
86
|
+
'Content-Type': 'application/json'
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
body: summary,
|
|
90
|
+
commit_id: commit,
|
|
91
|
+
event: 'COMMENT',
|
|
92
|
+
comments,
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
if(!res.ok) throw new Error(`${res.status} ${await res.text()}`);
|
|
96
|
+
}
|
|
97
|
+
console.log(comments.map(c => `${c.path}${c.new_position ? `:${c.new_position}` : ''}\n${c.body}`).join('\n\n') + '\n\n' + summary);
|
|
98
|
+
})();
|