feat(github): add github read pr & write comment tools to the github block, tested & works

This commit is contained in:
Waleed Latif
2025-02-24 00:03:58 -08:00
parent 3f4e6041ce
commit 9ff1783dcf
5 changed files with 387 additions and 19 deletions

122
tools/github/comment.ts Normal file
View File

@@ -0,0 +1,122 @@
import { ToolConfig } from '../types'
import { CreateCommentParams, CreateCommentResponse } from './types'
export const commentTool: ToolConfig<CreateCommentParams, CreateCommentResponse> = {
id: 'github_comment',
name: 'GitHub PR Commenter',
description: 'Create comments on GitHub PRs',
version: '1.0.0',
params: {
owner: {
type: 'string',
required: true,
description: 'Repository owner',
},
repo: {
type: 'string',
required: true,
description: 'Repository name',
},
pullNumber: {
type: 'number',
required: true,
description: 'Pull request number',
},
body: {
type: 'string',
required: true,
description: 'Comment content',
},
path: {
type: 'string',
required: false,
description: 'File path for review comment',
},
position: {
type: 'number',
required: false,
description: 'Line number for review comment',
},
apiKey: {
type: 'string',
required: true,
requiredForToolCall: true,
description: 'GitHub API token',
},
commentType: {
type: 'string',
required: false,
description: 'Type of comment (pr_comment or file_comment)',
},
line: {
type: 'number',
required: false,
description: 'Line number for review comment',
},
side: {
type: 'string',
required: false,
description: 'Side of the diff (LEFT or RIGHT)',
default: 'RIGHT',
},
commitId: {
type: 'string',
required: false,
description: 'The SHA of the commit to comment on',
},
},
request: {
url: (params) => {
if (params.path) {
return `https://api.github.com/repos/${params.owner}/${params.repo}/pulls/${params.pullNumber}/comments`
} else {
return `https://api.github.com/repos/${params.owner}/${params.repo}/pulls/${params.pullNumber}/reviews`
}
},
method: 'POST',
headers: (params) => ({
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${params.apiKey}`,
'X-GitHub-Api-Version': '2022-11-28',
}),
body: (params) => {
if (params.commentType === 'file_comment') {
return {
body: params.body,
commit_id: params.commitId,
path: params.path,
line: params.line || params.position,
side: params.side || 'RIGHT',
}
}
return {
body: params.body,
event: 'COMMENT',
}
},
},
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
body: data.body,
path: data.path,
line: data.line || data.position,
side: data.side,
commit_id: data.commit_id,
created_at: data.created_at,
updated_at: data.updated_at,
html_url: data.html_url,
},
}
},
transformError: (error) => {
return error instanceof Error ? error.message : 'Failed to create comment'
},
}

86
tools/github/pr.ts Normal file
View File

@@ -0,0 +1,86 @@
import { ToolConfig } from '../types'
import { PROperationParams, PullRequestResponse } from './types'
export const prTool: ToolConfig<PROperationParams, PullRequestResponse> = {
id: 'github_pr',
name: 'GitHub PR Reader',
description: 'Fetch PR details including diff and files changed',
version: '1.0.0',
params: {
owner: {
type: 'string',
required: true,
description: 'Repository owner',
},
repo: {
type: 'string',
required: true,
description: 'Repository name',
},
pullNumber: {
type: 'number',
required: true,
description: 'Pull request number',
},
apiKey: {
type: 'string',
required: true,
requiredForToolCall: true,
description: 'GitHub API token',
},
},
request: {
url: (params) =>
`https://api.github.com/repos/${params.owner}/${params.repo}/pulls/${params.pullNumber}`,
method: 'GET',
headers: (params) => ({
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response) => {
const pr = await response.json()
// Fetch the PR diff
const diffResponse = await fetch(pr.diff_url)
const diff = await diffResponse.text()
// Fetch files changed
const filesResponse = await fetch(
`https://api.github.com/repos/${pr.base.repo.owner.login}/${pr.base.repo.name}/pulls/${pr.number}/files`
)
const files = await filesResponse.json()
return {
success: true,
output: {
number: pr.number,
title: pr.title,
body: pr.body || '',
state: pr.state,
html_url: pr.html_url,
diff_url: pr.diff_url,
created_at: pr.created_at,
updated_at: pr.updated_at,
diff,
files: files.map((file: any) => ({
filename: file.filename,
additions: file.additions,
deletions: file.deletions,
changes: file.changes,
patch: file.patch,
blob_url: file.blob_url,
raw_url: file.raw_url,
status: file.status,
})),
},
}
},
transformError: (error) => {
return error instanceof Error ? error.message : 'Failed to fetch PR details'
},
}

65
tools/github/types.ts Normal file
View File

@@ -0,0 +1,65 @@
import { ToolResponse } from '../types'
export interface PullRequestResponse extends ToolResponse {
output: {
number: number
title: string
body: string
state: string
html_url: string
diff_url: string
created_at: string
updated_at: string
files?: {
filename: string
additions: number
deletions: number
changes: number
patch?: string
blob_url: string
raw_url: string
status: string
}[]
comments?: {
id: number
body: string
path?: string
line?: number
commit_id: string
created_at: string
updated_at: string
html_url: string
}[]
}
}
export interface CreateCommentResponse extends ToolResponse {
output: {
id: number
body: string
path?: string
line?: number
side?: string
commit_id?: string
created_at: string
updated_at: string
html_url: string
}
}
export interface PROperationParams {
owner: string
repo: string
pullNumber: number
apiKey: string
}
export interface CreateCommentParams extends PROperationParams {
body: string
path?: string
position?: number
line?: number // Add line number support
side?: string // Add side parameter
commitId?: string
commentType?: 'pr_comment' | 'file_comment' // Add comment type
}

View File

@@ -4,6 +4,8 @@ import { chatTool as deepseekChat } from './deepseek/chat'
import { reasonerTool as deepseekReasoner } from './deepseek/reasoner'
import { scrapeTool } from './firecrawl/scrape'
import { functionExecuteTool as functionExecute } from './function/execute'
import { commentTool } from './github/comment'
import { prTool } from './github/pr'
import { repoInfoTool } from './github/repo'
import { gmailReadTool } from './gmail/read'
import { gmailSearchTool } from './gmail/search'
@@ -68,6 +70,8 @@ export const tools: Record<string, ToolConfig> = {
pinecone_generate_embeddings: pineconeGenerateEmbeddingsTool,
pinecone_search_text: pineconeSearchTextTool,
pinecone_upsert_text: pineconeUpsertTextTool,
github_pr: prTool,
github_comment: commentTool,
}
// Get a tool by its ID