-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arihan/mar 8 ability to comment by line of code in pr #55
Changes from 60 commits
48df5f7
88e74d3
80ce114
5088ffa
5b1cef8
49d3193
c01b888
5f0696c
5ddc312
3f8b119
72074e9
0da48d1
484e2f9
f9092cc
4a651be
707aac3
eea274f
fba6cfc
54179b8
4e34447
836883e
2b5384e
9b6b922
cd7d978
482f313
6666976
a009c12
7eec620
d291152
d909615
a1016db
8a86bad
a20406d
be974c6
b1626ed
a05c2b6
3bd0960
78ad53a
16729c8
101df88
b27846f
f429951
57bbc1e
10dde12
b6e26e2
6e8691e
54dbda1
169e35d
9aaf357
2b592dd
058459e
949214a
086083a
9887f0e
2462800
8b5dde6
4160457
a9534f0
c2e2a2e
0c4b925
2f9e7f2
73b29f5
61631e0
129f403
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -167,60 +167,24 @@ export const POST = async (req: Request) => { | |
if (comment && !comment.body.toLowerCase().includes('maige')) | ||
return new Response('Irrelevant comment', {status: 202}) | ||
|
||
if (issue?.pull_request) { | ||
const { | ||
pull_request: {diff_url: diffUrl}, | ||
node_id: pullId | ||
} = issue | ||
|
||
// Get GitHub app instance access token | ||
const app = new App({ | ||
appId: process.env.GITHUB_APP_ID || '', | ||
privateKey: process.env.GITHUB_PRIVATE_KEY || '' | ||
}) | ||
|
||
const octokit = await app.getInstallationOctokit(instanceId) | ||
|
||
const response = await fetch(diffUrl) | ||
|
||
if (!response.ok) return new Response('Could not fetch diff', {status: 503}) | ||
|
||
const data = await response.text() | ||
|
||
await reviewer({ | ||
octokit: octokit, | ||
input: `Instruction: ${comment?.body}\n\nPR Diff:\n${data}`, | ||
pullId | ||
}) | ||
|
||
return new Response('Reviewed PR', {status: 200}) | ||
} | ||
|
||
if ( | ||
!( | ||
(action === 'opened' && payload?.issue) || | ||
(action === 'created' && payload?.comment) | ||
(action === 'created' && payload?.comment) || | ||
(action === 'opened' && payload?.pull_request) || | ||
(action === 'synchronize' && payload?.pull_request) | ||
) | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? |
||
return new Response('Webhook received', {status: 202}) | ||
|
||
const { | ||
issue: { | ||
node_id: issueId, | ||
title, | ||
number: issueNumber, | ||
body, | ||
labels: existingLabels | ||
}, | ||
repository: { | ||
node_id: repoId, | ||
name, | ||
owner: {login: owner} | ||
} | ||
} = payload | ||
|
||
const existingLabelNames = existingLabels?.map((l: Label) => l.name) | ||
|
||
const customer = await prisma.customer.findUnique({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving?
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
where: { | ||
name: owner || undefined | ||
|
@@ -289,6 +253,60 @@ export const POST = async (req: Request) => { | |
|
||
await incrementUsage(prisma, owner) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? |
||
|
||
if ((action == 'opened' || action == 'synchronize') && payload.pull_request) { | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const { | ||
pull_request: {diff_url: diffUrl} | ||
} = payload | ||
|
||
const res = await fetch(diffUrl) | ||
if (!res.ok) return new Response('Could not fetch diff', {status: 503}) | ||
const diff = await res.text() | ||
|
||
await reviewer({ | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
customerId, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? |
||
octokit, | ||
input: `Instruction: ${comment?.body}\n\nPR Diff:\n${diff}`, | ||
pullNumber: payload.number, | ||
repoFullName: `${owner}/${name}`, | ||
commitId: payload.pull_request.head.sha | ||
}) | ||
|
||
return new Response('Reviewed PR', {status: 200}) | ||
} | ||
|
||
if (issue?.pull_request) { | ||
const { | ||
pull_request: {diff_url: diffUrl}, | ||
node_id: pullId | ||
} = issue | ||
|
||
const res = await fetch(diffUrl) | ||
if (!res.ok) return new Response('Could not fetch diff', {status: 503}) | ||
const diff = await res.text() | ||
|
||
await reviewer({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? |
||
customerId, | ||
octokit, | ||
input: `Instruction: ${comment?.body}\n\nPR Diff:\n${diff}`, | ||
pullId, | ||
repoFullName: `${owner}/${name}` | ||
}) | ||
|
||
return new Response('Replied to PR comment', {status: 200}) | ||
} | ||
|
||
const { | ||
issue: { | ||
node_id: issueId, | ||
title, | ||
number: issueNumber, | ||
body, | ||
labels: existingLabels | ||
} | ||
} = payload | ||
|
||
const existingLabelNames = existingLabels?.map((l: Label) => l.name) | ||
|
||
/** | ||
* Repo commands | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
import {initializeAgentExecutorWithOptions} from 'langchain/agents' | ||
import {ChatOpenAI} from 'langchain/chat_models/openai' | ||
import {SerpAPI} from 'langchain/tools' | ||
import parse, {Change, Chunk} from 'parse-diff' | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import env from '~/env.mjs' | ||
import {codeComment} from '~/tools/codeComment' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like the By Maige. How's my driving? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. YO THIS REVIEWING FEATURE IS SICK @arihanv flagging this (as a much higher-level PR review than usual, which is SICK): Since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like you're importing By Maige. How's my driving? |
||
import {codebaseSearch} from '~/tools/codeSearch' | ||
import {prComment} from '~/tools/prComment' | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import {isDev} from '~/utils' | ||
|
||
|
@@ -12,36 +15,110 @@ const model = new ChatOpenAI({ | |
}) | ||
|
||
export async function reviewer({ | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The By Maige. How's my driving? |
||
customerId, | ||
input, | ||
octokit, | ||
pullId | ||
pullId, | ||
repoFullName, | ||
pullNumber, | ||
commitId | ||
}: { | ||
customerId: string | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
input: string | ||
octokit: any | ||
pullId: string | ||
pullId?: string | ||
repoFullName?: string | ||
pullNumber?: number | ||
commitId?: string | ||
}) { | ||
const tools = [new SerpAPI(), prComment({octokit, pullId})] | ||
|
||
const prefix = ` | ||
You are senior engineer reviewing a Pull Request in GitHub made by a junior engineer. | ||
You MUST leave a comment on the PR according to the user's instructions using the prComment function. | ||
Format your answer beautifully using markdown suitable for GitHub. | ||
DO NOT use any emojis or non-Ascii characters. | ||
{agent_scratchpad} | ||
`.replaceAll('\n', ' ') | ||
|
||
const executor = await initializeAgentExecutorWithOptions(tools, model, { | ||
agentType: 'openai-functions', | ||
returnIntermediateSteps: isDev, | ||
handleParsingErrors: true, | ||
verbose: false, | ||
agentArgs: { | ||
prefix | ||
/** | ||
* Comment on a PR | ||
*/ | ||
if (pullId) { | ||
const tools = [new SerpAPI(), codebaseSearch({customerId, repoFullName})] | ||
|
||
const prefix = ` | ||
You are a 1000x senior engineer summarizing a pull request on GitHub. | ||
Provide a high-level summary (maximum 5 sentences) of the diff. | ||
If you write too much, the author will get overwhelmed. | ||
Limit prose. | ||
|
||
{agent_scratchpad} | ||
`.replaceAll('\n', ' ') | ||
|
||
const executor = await initializeAgentExecutorWithOptions(tools, model, { | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
agentType: 'openai-functions', | ||
returnIntermediateSteps: isDev, | ||
handleParsingErrors: true, | ||
verbose: true, | ||
agentArgs: { | ||
prefix | ||
} | ||
}) | ||
|
||
const result = await executor.call({input}) | ||
|
||
// Forcefully call the prComment tool | ||
await prComment({octokit, pullId}).func({ | ||
comment: result.output | ||
}) | ||
|
||
return | ||
} else { | ||
/** | ||
* New or updated PR | ||
*/ | ||
const prefix = ` | ||
tedspare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
You are a 1000x senior engineer reviewing a pull request on GitHub. | ||
Only comment on modified code. | ||
Only flag the top few issues: bad patterns, clear mistakes, or potential breaking changes. | ||
If it looks like new code is unused, try searching for it. | ||
Think step by step. | ||
Limit prose. If you write too much, the author will get overwhelmed. | ||
|
||
{agent_scratchpad} | ||
`.replaceAll('\n', ' ') | ||
|
||
let files = parse(input) | ||
let diff = '' | ||
|
||
for (const file of files) { | ||
let changes = `File Path: ${file.from}\n\n` | ||
|
||
file.chunks.forEach((chunk: Chunk) => { | ||
chunk.changes.forEach((change: Change & {ln2?: string; ln?: string}) => { | ||
const line = change.content.replaceAll('\t', ' ') | ||
changes += `${change.ln2 || change.ln} ${line}\n` | ||
}) | ||
|
||
changes += '='.repeat(10) + '\n' | ||
}) | ||
|
||
diff += changes + '='.repeat(20) + '\n\n' | ||
} | ||
}) | ||
|
||
const result = await executor.call({input}) | ||
const {output} = result | ||
const tools = [ | ||
codebaseSearch({customerId, repoFullName}), | ||
codeComment({ | ||
octokit, | ||
repoFullName, | ||
pullNumber, | ||
commitId | ||
}) | ||
] | ||
|
||
const executor = await initializeAgentExecutorWithOptions(tools, model, { | ||
agentType: 'openai-functions', | ||
returnIntermediateSteps: isDev, | ||
handleParsingErrors: true, | ||
verbose: true, | ||
agentArgs: { | ||
prefix | ||
} | ||
}) | ||
|
||
await executor.call({input: diff}) | ||
|
||
return output | ||
return | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import {DynamicStructuredTool} from 'langchain/tools' | ||
import {z} from 'zod' | ||
import {COPY} from '~/constants' | ||
|
||
/** | ||
* Comment on code | ||
*/ | ||
export function codeComment({ | ||
octokit, | ||
repoFullName, | ||
pullNumber, | ||
commitId | ||
}: { | ||
octokit: any | ||
repoFullName: string | ||
pullNumber: number | ||
commitId: string | ||
}) { | ||
return new DynamicStructuredTool({ | ||
description: 'Adds a comment to code in a PR', | ||
func: async ({comment, line, side, path}) => { | ||
const res = await octokit.request( | ||
`POST /repos/${repoFullName}/pulls/${pullNumber}/comments`, | ||
{ | ||
body: `${comment}\n\n${COPY.FOOTER}`, | ||
commit_id: commitId, | ||
path, | ||
line, | ||
side, | ||
headers: {'X-GitHub-Api-Version': '2022-11-28'} | ||
} | ||
) | ||
return JSON.stringify(res) | ||
}, | ||
name: 'codeComment', | ||
schema: z.object({ | ||
comment: z.string().describe('The comment to add'), | ||
line: z.number().describe('The line number'), | ||
side: z | ||
.enum(['LEFT', 'RIGHT']) | ||
.describe('If Deletion then LEFT, else RIGHT'), | ||
path: z.string().describe('The path to the file') | ||
}) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new changes in the webhook route do not include a check for the 'maige' keyword in the comment body, which was present in the original code. This could potentially allow irrelevant comments to trigger the webhook actions.
By Maige. How's my driving?