@ztimson/ai-agents 0.0.3 → 0.0.5

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 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,86 @@
1
- <!-- Header -->
2
- <div id="top" align="center">
3
- <br />
4
-
5
- <!-- Logo -->
6
- <img src="https://git.zakscode.com/repo-avatars/d2c56ffd0220751c2f4a9f6fc1e8125a9a63aeed452ae4f4ab696c084330faa2" 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
- [![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ai-agents/tags&query=$[0].name)](https://git.zakscode.com/ztimson/ai-agents/tags)
16
- [![Pull Requests](https://img.shields.io/badge/dynamic/json.svg?label=Pull%20Requests&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ai-agents&query=open_pr_counter)](https://git.zakscode.com/ztimson/ai-agents/pulls)
17
- [![Issues](https://img.shields.io/badge/dynamic/json.svg?label=Issues&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ai-agents&query=open_issues_count)](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
- [![Docker](https://img.shields.io/badge/Docker-384d54?style=for-the-badge&logo=docker)](https://docker.com/)
44
- [![JavaScript](https://img.shields.io/badge/JavaScript-000000?style=for-the-badge&logo=javascript)](https://javascript.com/)
45
- [![Node](https://img.shields.io/badge/Node.js-000000?style=for-the-badge&logo=nodedotjs)](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
- #### Instructions
57
- 1. Run using npx: `npx @ztimson/ai-agents review`
58
-
59
- </details>
60
-
61
- <details>
62
- <summary>
63
- <h3 id="development" style="display: inline">
64
- Development
65
- </h3>
66
- </summary>
67
-
68
- #### Prerequisites
69
- - [Node.js](https://nodejs.org/en/download)
70
-
71
- #### Instructions
72
- 1. Install the dependencies: `npm i`
73
- 2. Build library: `npm run review`
74
-
75
- </details>
76
-
77
- ## License
78
-
79
- Copyright © 2025 Zakary Timson | All Rights Reserved | Available under MIT Licensing
80
-
81
- See the [license](./LICENSE) for more information.
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
+ AI-powered Gitea agents for automating reviews and administration
13
+
14
+ <!-- Repo badges -->
15
+ [![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ai-agents/tags&query=$[0].name)](https://git.zakscode.com/ztimson/ai-agents/tags)
16
+ [![Pull Requests](https://img.shields.io/badge/dynamic/json.svg?label=Pull%20Requests&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ai-agents&query=open_pr_counter)](https://git.zakscode.com/ztimson/ai-agents/pulls)
17
+ [![Issues](https://img.shields.io/badge/dynamic/json.svg?label=Issues&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ai-agents&query=open_issues_count)](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
+ Only supports Gitea
41
+
42
+ Use LLM models from Anthropic, OpenAI, or Ollama to automate ticket refinement, code reviews, and releases.
43
+
44
+ ### Built With
45
+ [![Docker](https://img.shields.io/badge/Docker-384d54?style=for-the-badge&logo=docker)](https://docker.com/)
46
+ [![JavaScript](https://img.shields.io/badge/JavaScript-000000?style=for-the-badge&logo=javascript)](https://javascript.com/)
47
+ [![Node](https://img.shields.io/badge/Node.js-000000?style=for-the-badge&logo=nodedotjs)](https://nodejs.org/)
48
+
49
+ ## Setup
50
+
51
+ <details>
52
+ <summary>
53
+ <h3 id="production" style="display: inline">
54
+ Production
55
+ </h3>
56
+ </summary>
57
+
58
+ #### Prerequisites
59
+ - [Node.js](https://nodejs.org/en/download)
60
+
61
+ #### Instructions
62
+ 1. Run using npx: `npx -y @ztimson/ai-agents@latest review`
63
+
64
+ </details>
65
+
66
+ <details>
67
+ <summary>
68
+ <h3 id="development" style="display: inline">
69
+ Development
70
+ </h3>
71
+ </summary>
72
+
73
+ #### Prerequisites
74
+ - [Node.js](https://nodejs.org/en/download)
75
+
76
+ #### Instructions
77
+ 1. Install the dependencies: `npm i`
78
+ 2. Build library: `npm run review`
79
+
80
+ </details>
81
+
82
+ ## License
83
+
84
+ Copyright © 2025 Zakary Timson | All Rights Reserved | Available under MIT Licensing
85
+
86
+ See the [license](./LICENSE) for more information.
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@ztimson/ai-agents",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
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
+ "refine": "./src/refine.mjs",
10
11
  "review": "./src/review.mjs"
11
12
  },
12
13
  "dependencies": {
package/src/refine.mjs ADDED
@@ -0,0 +1,172 @@
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
+ const git = process.env['GIT_HOST'],
18
+ owner = process.env['GIT_OWNER'],
19
+ repo = process.env['GIT_REPO'],
20
+ auth = process.env['GIT_TOKEN'],
21
+ ticket = process.env['TICKET'],
22
+ host = process.env['AI_HOST'],
23
+ model = process.env['AI_MODEL'],
24
+ token = process.env['AI_TOKEN'];
25
+
26
+ console.log(`Processing issue #${ticket}`);
27
+
28
+ // Fetch issue
29
+ const issueRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, {
30
+ headers: {'Authorization': `token ${auth}`}
31
+ });
32
+ if(!issueRes.ok) throw new Error(`${issueRes.status} ${await issueRes.text()}`);
33
+ const issueData = await issueRes.json();
34
+ if(!issueData.labels?.some(l => l.name === 'Review/AI')) {
35
+ console.log('Skipping');
36
+ return process.exit();
37
+ }
38
+
39
+ let title = '', type = '', readme = '', readmeP = path.join(process.cwd(), 'README.md');
40
+ if(fs.existsSync(readmeP)) readme = fs.readFileSync(readmeP, 'utf-8');
41
+ const template = p ? fs.readFileSync(p, 'utf-8') : `## Description
42
+
43
+ A clear explanation of the request
44
+
45
+ ---
46
+
47
+ ## Current Behavior
48
+
49
+ what's happening now or the current state/gap
50
+
51
+ ## Expected Behavior
52
+
53
+ What should happen instead
54
+
55
+ ## Steps to Reproduce / Desired Flow
56
+
57
+ 1. First step
58
+ 2. Second step
59
+ 3. Third step
60
+
61
+ ## Additional Context
62
+
63
+ Logs, screenshots, links, related issues
64
+
65
+ ## Acceptance Criteria
66
+
67
+ - [ ] Todo requirement
68
+ - [X] Completed requirement
69
+
70
+ ## Technical Notes
71
+
72
+ Implementation details, constraints, dependencies, design decisions
73
+
74
+
75
+ | Effort / Weight | Score |
76
+ |-----------------|----------|
77
+ | Size | 0-5 |
78
+ | Complexity | 0-5 |
79
+ | Unknowns | 0-5 |
80
+ | **Total** | **0-15** |
81
+ `;
82
+
83
+ let options = {ollama: {model, host}};
84
+ if(host === 'anthropic') options = {anthropic: {model, token}};
85
+ else if(host === 'openai') options = {openAi: {model, token}};
86
+ const ai = new Ai({
87
+ ...options,
88
+ model: [host, model],
89
+ path: process.env['path'] || os.tmpdir(),
90
+ tools: [{
91
+ name: 'title',
92
+ description: 'Set the ticket title, must be called EXACTLY ONCE',
93
+ args: {value: {type: 'string', description: 'Ticket title, must match format: [Module] - [Verb] [noun]', required: true}},
94
+ fn: (args) => title = args.title
95
+ }, {
96
+ name: 'type',
97
+ description: 'Set the ticket type, must be called EXACTLY ONCE',
98
+ args: {type: {type: 'string', description: 'Ticket type', enum: ['Bug', 'DevOps', 'Document', 'Enhancement', 'Refactor', 'Security'], required: true}},
99
+ fn: (args) => type = args.type
100
+ }],
101
+ system: `Transform raw tickets into structured markdown following the template EXACTLY.
102
+
103
+ **MANDATORY STEPS:**
104
+ 1. Identify ticket type: Bug, DevOps, Document, Enhancement, Refactor, or Security
105
+ 2. Call \`type\` tool EXACTLY ONCE with the type from step 1
106
+ 3. Call \`title\` tool EXACTLY ONCE in format: "[Module] - [Verb] [subject]"
107
+ 4. Output formatted markdown matching template structure below
108
+
109
+ **TEMPLATE RULES:**
110
+ - Use ## headers (match template exactly)
111
+ - Description: Clear summary of the request
112
+ - Current Behavior: What's happening now (remove for Document tickets)
113
+ - Expected Behavior: What should happen (remove for Document tickets)
114
+ - Steps to Reproduce: Numbered list for bugs, flow for enhancements, remove if not applicable
115
+ - Additional Context: Logs, screenshots, links provided by user
116
+ - Acceptance Criteria: Convert to checkboxes (- [ ] format)
117
+ - Technical Notes: Implementation approach, constraints, dependencies
118
+ - Weight table (use exact format below):
119
+
120
+ | Effort / Weight | Score |
121
+ |-----------------|----------|
122
+ | Size | 0-5 |
123
+ | Complexity | 0-5 |
124
+ | Unknowns | 0-5 |
125
+ | **Total** | **0-15** |
126
+
127
+ **SCORING:**
128
+ - Size: # of modules/layers/files changed
129
+ - Complexity: Technical difficulty
130
+ - Unknowns: Research/uncertainty needed
131
+
132
+ **README:**
133
+ \`\`\`markdown
134
+ ${readme.trim() || 'No README available'}
135
+ \`\`\`
136
+
137
+ **TEMPLATE:**
138
+ \`\`\`markdown
139
+ ${template.trim()}
140
+ \`\`\`
141
+
142
+ Output ONLY markdown. No explanations, labels, or extra formatting.`});
143
+
144
+ const messages = await ai.language.ask(`Title: ${issueData.title}\n\nDescription:\n${issueData.body || 'No description provided'}`).catch(() => []);
145
+ const body = messages?.pop()?.content;
146
+ if(!body) {
147
+ console.log('Invalid response from AI');
148
+ return process.exit(1);
149
+ }
150
+ const updateRes = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}`, {
151
+ method: 'PATCH',
152
+ headers: {
153
+ 'Authorization': `token ${auth}`,
154
+ 'Content-Type': 'application/json'
155
+ },
156
+ body: JSON.stringify({
157
+ title,
158
+ body,
159
+ })
160
+ });
161
+ if(!updateRes.ok) throw new Error(`${updateRes.status} ${await updateRes.text()}`);
162
+ if(type) fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}/labels`, {
163
+ method: 'POST',
164
+ headers: {
165
+ 'Authorization': `token ${auth}`,
166
+ 'Content-Type': 'application/json'
167
+ },
168
+ body: `["Kind/${type[0].toUpperCase() + type.slice(1).toLowerCase()}"]`
169
+ })
170
+
171
+ console.log(`Title: ${title}\nType: ${type}\nBody:\n${body}`);
172
+ })();
package/src/review.mjs CHANGED
@@ -30,6 +30,22 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
30
30
  const commit = await $`cd ${root} && git log -1 --pretty=format:%H`;
31
31
  const gitDiff = await $`cd ${root} && git diff ${branch}`;
32
32
 
33
+ if(!gitDiff) {
34
+ console.warn('No diff found');
35
+ return process.exit();
36
+ }
37
+
38
+ let existingComments = 'Existing Comments:\n';
39
+ if(git && pr) {
40
+ const reviews = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}/reviews`, {
41
+ headers: {'Authorization': `token ${auth}`}
42
+ }).then(resp => resp.ok ? resp.json() : []);
43
+ const comments = await Promise.all(reviews.map(r => fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}/reviews/${r.id}/comments`, {
44
+ headers: {'Authorization': `token ${auth}`}
45
+ }).then(resp => resp.ok ? resp.json() : [])));
46
+ existingComments += comments.flatten().map(c => `${c.path}:${c.position}\n${c.body}`).join('\n\n');
47
+ }
48
+
33
49
  let options = {ollama: {model, host}};
34
50
  if(host === 'anthropic') options = {anthropic: {model, token}};
35
51
  else if(host === 'openai') options = {openAi: {model, token}};
@@ -37,7 +53,7 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
37
53
  ...options,
38
54
  model: [host, model],
39
55
  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.`,
56
+ 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}`,
41
57
  tools: [{
42
58
  name: 'read_file',
43
59
  description: 'Read contents of a file',
@@ -71,11 +87,6 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
71
87
  }]
72
88
  });
73
89
 
74
- if(!gitDiff) {
75
- console.warn('No diff found');
76
- return process.exit();
77
- }
78
-
79
90
  const messages = await ai.language.ask(gitDiff);
80
91
  const summary = messages.pop().content;
81
92
  if(git) {