From 677f84c97a04343162abac632b1f5a902ef9eee5 Mon Sep 17 00:00:00 2001 From: ztimson Date: Wed, 14 Jan 2026 13:38:20 -0500 Subject: [PATCH 1/4] Added label to enable review bot on PRs --- .github/pull_request_template.md | 4 +--- .github/workflows/code-review.yml | 2 +- .github/workflows/ticket-refinement.yml | 1 + package.json | 2 +- src/refine.mjs | 3 ++- src/review.mjs | 10 +++++++++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a5bdd82..b8847c1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -9,7 +9,5 @@ ## Checklist - - [ ] Linked issues - - [ ] Reviewed changes + - [ ] Reviewed changes (or use `Review/AI` label) - [ ] Updated comments/documentation - \ No newline at end of file diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index 6401af7..78ef451 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -2,7 +2,7 @@ name: Code review on: pull_request: - types: [opened, synchronize, reopened] + types: [opened, synchronize, reopened, labeled] jobs: review: diff --git a/.github/workflows/ticket-refinement.yml b/.github/workflows/ticket-refinement.yml index 1412945..ac728ec 100644 --- a/.github/workflows/ticket-refinement.yml +++ b/.github/workflows/ticket-refinement.yml @@ -3,6 +3,7 @@ name: Ticket refinement on: issues: types: [labeled] + jobs: format: runs-on: ubuntu-latest diff --git a/package.json b/package.json index 3789c7f..56f036b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ztimson/ai-agents", - "version": "0.1.1", + "version": "0.1.2", "description": "AI agents", "keywords": ["ai", "review"], "author": "ztimson", diff --git a/src/refine.mjs b/src/refine.mjs index 9ce3b9c..b01c496 100644 --- a/src/refine.mjs +++ b/src/refine.mjs @@ -181,8 +181,9 @@ Output ONLY markdown. No explanations, labels, or extra formatting.`}); const hasDuplicates = (await ai.language.ask(`ID: ${issueData.id}\nTitle: ${title}\n\`\`\`markdown\n${body}\n\`\`\``, { system: `Your job is to identify duplicates. Respond ONLY with the duplicate's ID number or "NONE" if no match exists\n\n${dupes}` }))?.pop()?.content; + // Handle duplicates - if(hasDuplicates && hasDuplicates !== 'NONE' && (dupeId = dupeIds.find(id => id == hasDuplicates.trim()))) { + if(hasDuplicates && !hasDuplicates.toUpperCase().includes('NONE') && (dupeId = dupeIds.find(id => id == hasDuplicates.trim())) != null && dupeId != issueData.id) { await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues/${ticket}/comments`, { method: 'POST', headers: {'Authorization': `token ${auth}`, 'Content-Type': 'application/json'}, diff --git a/src/review.mjs b/src/review.mjs index e1c87a3..bf35503 100644 --- a/src/review.mjs +++ b/src/review.mjs @@ -19,12 +19,20 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false}); owner = process.env['GIT_OWNER'], repo = process.env['GIT_REPO'], auth = process.env['GIT_TOKEN'], + labelEnabled = process.env['LABEL_ENABLED'] || 'Review/AI', pr = process.env['PULL_REQUEST'], host = process.env['AI_HOST'], model = process.env['AI_MODEL'], token = process.env['AI_TOKEN']; console.log(`Reviewing: ${root}\n`); + const info = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}`) + .then(async resp => { return resp.ok ? resp.json() : throw new Error(`${resp.status} ${await resp.text()}`); }); + if(info.labels?.length > 0 || !info.labels.some(l => l.name === labelEnabled)) { + console.log('Skipping'); + return process.exit(); + } + const branch = process.env['GIT_BRANCH'] || await $`cd ${root} && git symbolic-ref refs/remotes/origin/HEAD`; const comments = []; const commit = await $`cd ${root} && git log -1 --pretty=format:%H`; @@ -53,7 +61,7 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false}); ...options, model: [host, model], path: process.env['path'] || os.tmpdir(), - 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}`, + 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 a quick 75 words or less sitrep.${existingComments}`, tools: [{ name: 'read_file', description: 'Read contents of a file', From 1460c3a0ae1af7f97953859b545211f28708f3d8 Mon Sep 17 00:00:00 2001 From: ztimson Date: Wed, 14 Jan 2026 13:44:31 -0500 Subject: [PATCH 2/4] Added PR info as context to AI --- src/review.mjs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/review.mjs b/src/review.mjs index bf35503..e5545d9 100644 --- a/src/review.mjs +++ b/src/review.mjs @@ -95,7 +95,16 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false}); }] }); - const messages = await ai.language.ask(gitDiff); + const messages = await ai.language.ask(`Title: ${info.title} +Description: +\`\`\`md +${info.body} +\`\`\` + +Git Diff: +\`\`\` +${gitDiff} +\`\`\``); const summary = messages.pop().content; if(git) { const res = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}/reviews`, { From 3b01e1bfc1d03088ff7bee51e361a76d3dcf4afe Mon Sep 17 00:00:00 2001 From: ztimson Date: Wed, 14 Jan 2026 13:51:41 -0500 Subject: [PATCH 3/4] =?UTF-8?q?Fixed=20label=20condition=20check=20?= =?UTF-8?q?=F0=9F=92=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/review.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/review.mjs b/src/review.mjs index e5545d9..352e071 100644 --- a/src/review.mjs +++ b/src/review.mjs @@ -28,7 +28,7 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false}); console.log(`Reviewing: ${root}\n`); const info = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}`) .then(async resp => { return resp.ok ? resp.json() : throw new Error(`${resp.status} ${await resp.text()}`); }); - if(info.labels?.length > 0 || !info.labels.some(l => l.name === labelEnabled)) { + if(info.labels?.length > 0 && !info.labels.some(l => l.name === labelEnabled)) { console.log('Skipping'); return process.exit(); } From 744720435135f5dbb04e33460adc1642d8fcbcb4 Mon Sep 17 00:00:00 2001 From: ztimson Date: Wed, 14 Jan 2026 14:05:41 -0500 Subject: [PATCH 4/4] Fixed more logic checks --- src/review.mjs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/review.mjs b/src/review.mjs index 352e071..8ff67e8 100644 --- a/src/review.mjs +++ b/src/review.mjs @@ -27,8 +27,11 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false}); console.log(`Reviewing: ${root}\n`); const info = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}`) - .then(async resp => { return resp.ok ? resp.json() : throw new Error(`${resp.status} ${await resp.text()}`); }); - if(info.labels?.length > 0 && !info.labels.some(l => l.name === labelEnabled)) { + .then(async resp => { + if(resp.ok) return resp.json(); + throw new Error(`${resp.status} ${await resp.text()}`); + }); + if(!info.labels.some(l => l.name === labelEnabled)) { console.log('Skipping'); return process.exit(); } @@ -95,10 +98,10 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false}); }] }); - const messages = await ai.language.ask(`Title: ${info.title} + const messages = await ai.language.ask(`Title: ${info.title || 'None'} Description: \`\`\`md -${info.body} +${info.body || 'None'} \`\`\` Git Diff: