Skip to content

Commit 00c5858

Browse files
authored
Merge pull request #1 from igtm/feature/igtm-mpuo
base implementation and add playground directory
2 parents c9f232a + d019ca0 commit 00c5858

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+6643
-0
lines changed
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
name: LLM Coder
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
9+
permissions:
10+
id-token: write
11+
contents: write
12+
pull-requests: write
13+
issues: write
14+
15+
jobs:
16+
llm-coder:
17+
if: |
18+
((github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') &&
19+
contains(github.event.comment.body, '/llm-coder')
20+
)
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Debug github.event
24+
run: cat $GITHUB_EVENT_PATH
25+
- name: Set environment variables
26+
run: |
27+
# Handle pull request events first
28+
if [ -n "${{ github.event.pull_request.number }}" ]; then
29+
echo "ISSUE_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
30+
echo "ISSUE_TYPE=pr" >> $GITHUB_ENV
31+
# Handle pull request review events
32+
elif [ -n "${{ github.event.review.body }}" ]; then
33+
echo "ISSUE_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
34+
echo "ISSUE_TYPE=pr" >> $GITHUB_ENV
35+
# Handle issue comment events that reference a PR
36+
elif [ -n "${{ github.event.issue.pull_request }}" ]; then
37+
echo "ISSUE_NUMBER=${{ github.event.issue.number }}" >> $GITHUB_ENV
38+
echo "ISSUE_TYPE=pr" >> $GITHUB_ENV
39+
# Handle regular issue events
40+
else
41+
echo "ISSUE_NUMBER=${{ github.event.issue.number }}" >> $GITHUB_ENV
42+
echo "ISSUE_TYPE=issue" >> $GITHUB_ENV
43+
fi
44+
45+
if [ -n "${{ github.event.review.body }}" ]; then
46+
echo "COMMENT_ID=${{ github.event.review.id || 'None' }}" >> $GITHUB_ENV
47+
else
48+
echo "COMMENT_ID=${{ github.event.comment.id || 'None' }}" >> $GITHUB_ENV
49+
fi
50+
- name: React to trigger comment
51+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
52+
with:
53+
github-token: ${{ github.token }}
54+
script: |
55+
const issueType = process.env.ISSUE_TYPE;
56+
const commentId = process.env.COMMENT_ID;
57+
58+
if (commentId !== 'None') {
59+
try {
60+
if (context.eventName === 'pull_request_review_comment') {
61+
await github.rest.reactions.createForPullRequestReviewComment({
62+
owner: context.repo.owner,
63+
repo: context.repo.repo,
64+
comment_id: commentId,
65+
content: 'eyes'
66+
});
67+
} else {
68+
await github.rest.reactions.createForIssueComment({
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
comment_id: commentId,
72+
content: 'eyes'
73+
});
74+
}
75+
} catch (error) {
76+
console.log('Failed to create reaction:', error);
77+
}
78+
}
79+
- name: Checkout repository
80+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
81+
with:
82+
submodules: recursive
83+
- name: Set up Python
84+
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
85+
with:
86+
python-version: "3.13"
87+
- name: Setup LLM Coder from source
88+
run: |
89+
mkdir -p /tmp/llm-coder
90+
git clone https://github.com/igtm/llm-coder.git /tmp/llm-coder
91+
cd /tmp/llm-coder
92+
python -m pip install --upgrade pip
93+
pip install --editable .
94+
pip install boto3
95+
- name: Setup Docker
96+
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
97+
- name: Generate Problem Statement
98+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
99+
with:
100+
script: |
101+
let problemStatement = '';
102+
const isPullRequest = !!context.payload.issue?.pull_request;
103+
104+
if (context.eventName === 'issue_comment') {
105+
if (isPullRequest) {
106+
// PRへのコメントの場合
107+
const prNumber = context.payload.issue.number;
108+
// PRの情報を取得
109+
// const { data: pr } = await github.rest.pulls.get({
110+
// owner: context.repo.owner,
111+
// repo: context.repo.repo,
112+
// pull_number: prNumber
113+
// });
114+
115+
// 変更ファイル一覧を取得
116+
// const { data: files } = await github.rest.pulls.listFiles({
117+
// owner: context.repo.owner,
118+
// repo: context.repo.repo,
119+
// pull_number: prNumber
120+
// });
121+
122+
// const changedFiles = files.map(file => `- ${file.filename}`).join('\n');
123+
124+
problemStatement = `この指示に従ってコード修正してください:${context.payload.comment.body.replace('/llm-coder', '')}`;
125+
} else {
126+
// Issue へのコメントの場合
127+
problemStatement = `
128+
以下のGithub Issueの内容を解決できるようにコードを修正してください
129+
Issue のタイトル: ${context.payload.issue.title}
130+
Issue の本文: ${context.payload.issue.body}
131+
コメント: ${context.payload.comment.body.replace('/llm-coder', '')}
132+
`;
133+
}
134+
} else if (context.eventName === 'pull_request_review_comment') {
135+
// PR review comment の場合
136+
problemStatement = `
137+
以下の指示に従って指示がなされたファイルのみを修正してください:
138+
${context.payload.comment.body.replace('/llm-coder', '')}
139+
140+
指示がなされたファイル: ${context.payload.comment.path}
141+
指示がなされた行番号: ${context.payload.comment.line}
142+
143+
指示がなされたコードの周辺差分: ${context.payload.comment.diff_hunk}
144+
145+
注意:指示がなされたファイル以外の変更は行わないでください。基本は、指示がなされた行番号付近のコードを修正してください。
146+
`;
147+
}
148+
149+
console.log('Event Name:', context.eventName);
150+
console.log('Is Pull Request:', isPullRequest);
151+
core.exportVariable('PROBLEM_STATEMENT', problemStatement);
152+
- name: Run LLM Coder
153+
run: |
154+
# Escape newlines and quotes in problem statement
155+
ESCAPED_PROBLEM_STATEMENT=$(echo "$PROBLEM_STATEMENT" | awk '{printf "%s\\n", $0}' | sed 's/"/\\"/g')
156+
157+
llm-coder "$ESCAPED_PROBLEM_STATEMENT"
158+
env:
159+
GITHUB_TOKEN: ${{ github.token }}
160+
AWS_REGION_NAME: us-west-2
161+
- name: Prepare Git and Push Changes
162+
id: git_changes
163+
run: |
164+
# Configure git user
165+
git config user.email "noemail@igtm.link" && git config user.name "LLM-Coder"
166+
167+
# Apply patch
168+
git add .
169+
170+
# Check if there are any changes
171+
if ! git diff --staged --quiet; then
172+
echo "SKIP_REMAINING=false" >> $GITHUB_ENV
173+
# Issue comment かつ PR でない場合は新しいブランチを作成
174+
if [ "${{ github.event_name }}" = "issue_comment" ] && [ -z "${{ github.event.issue.pull_request }}" ]; then
175+
BRANCH_NAME="LLM-Coder-fix-#${{ env.ISSUE_NUMBER }}-$(echo $RANDOM | md5sum | cut -c1-8)"
176+
echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_ENV
177+
git checkout -b "$BRANCH_NAME"
178+
else
179+
# PR に対するコメントの場合は、その PR のブランチを使用
180+
PR_NUMBER=${{ env.ISSUE_NUMBER }}
181+
PR_DATA=$(gh pr view $PR_NUMBER --json headRefName)
182+
BRANCH_NAME=$(echo $PR_DATA | jq -r .headRefName)
183+
echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_ENV
184+
git fetch origin $BRANCH_NAME
185+
git stash --include-untracked
186+
git checkout $BRANCH_NAME
187+
git stash pop || true
188+
fi
189+
190+
git commit -m "Fixed by LLM-Coder" -m "Closes #${{ env.ISSUE_NUMBER }}"
191+
git push origin "$BRANCH_NAME"
192+
else
193+
echo "SKIP_REMAINING=true" >> $GITHUB_ENV
194+
echo "No changes to commit. LLM-Coder did not modify any files."
195+
exit 0
196+
fi
197+
env:
198+
GITHUB_TOKEN: ${{ github.token }}
199+
200+
- name: Install OpenAI Package
201+
if: env.SKIP_REMAINING != 'true'
202+
run: npm install openai @azure/openai
203+
204+
- name: Create Pull Request
205+
if: ${{ github.event_name == 'issue_comment' && !github.event.issue.pull_request && env.SKIP_REMAINING != 'true' }}
206+
continue-on-error: true
207+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
208+
env:
209+
OPENAI_API_KEY: ${{ secrets.LLM_API_KEY }}
210+
with:
211+
github-token: ${{ github.token }}
212+
script: |
213+
const { repo, owner } = context.repo;
214+
const issueUrl = context.payload.issue?.html_url;
215+
const issueNumber = process.env.ISSUE_NUMBER;
216+
217+
// Get issue title if available
218+
let issueTitle = "llm-coder";
219+
try {
220+
const issue = await github.rest.issues.get({
221+
owner,
222+
repo,
223+
issue_number: parseInt(issueNumber)
224+
});
225+
issueTitle = issue.data.title;
226+
} catch (error) {
227+
console.log('Could not fetch issue title:', error);
228+
}
229+
230+
// Get diff content
231+
const { execSync } = require('child_process');
232+
const diff = execSync('git diff HEAD^').toString();
233+
234+
// Generate PR description using OpenAI API
235+
const { OpenAI } = require("openai");
236+
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
237+
const modelName = '${{ vars.LLM_MODEL || 'gpt-4.1-nano' }}';
238+
const prompt = `Generate a concise Pull Request description based on the following git diff. Explain the main changes and their purpose. Format it nicely using Markdown.\n\nGit diff:\n\`\`\`diff\n${diff}\n\`\`\``;
239+
let generatedDescription = 'Automated code changes by LLM Coder.';
240+
try {
241+
const completion = await client.chat.completions.create({
242+
model: modelName, messages: [{ role: 'user', content: prompt }],
243+
});
244+
generatedDescription = completion.choices[0].message.content;
245+
} catch (error) {
246+
console.error("Error generating PR description:", error);
247+
}
248+
const prBody = `${generatedDescription}\n\n---\n*Created by LLM Coder based on [Issue #${issueNumber}](${context.payload.issue.html_url}).*\n*Triggered by [comment](${triggerCommentUrl}).*`;
249+
250+
const pr = await github.rest.pulls.create({
251+
owner,
252+
repo,
253+
title: `LLM-Coder[bot]: ${issueTitle}`,
254+
head: process.env.BRANCH_NAME,
255+
base: 'develop',
256+
body: prBody,
257+
draft: true
258+
});
259+
260+
console.log(`Pull Request created: ${pr.data.html_url}`);
261+
262+
- name: Add PR Comment
263+
if: ${{ (github.event_name != 'issue_comment' || github.event.issue.pull_request) && env.SKIP_REMAINING != 'true' }}
264+
continue-on-error: true
265+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
266+
env:
267+
OPENAI_API_KEY: ${{ secrets.LLM_API_KEY }}
268+
with:
269+
github-token: ${{ github.token }}
270+
script: |
271+
const { repo, owner } = context.repo;
272+
const prNumber = process.env.ISSUE_NUMBER;
273+
274+
// Get diff content
275+
const { execSync } = require('child_process');
276+
const diff = execSync('git diff HEAD^').toString();
277+
278+
const { OpenAI } = require("openai");
279+
const client = new OpenAI({
280+
apiKey: process.env.OPENAI_API_KEY,
281+
});
282+
const modelName = '${{ vars.LLM_MODEL || 'gpt-4.1-nano' }}';
283+
284+
const prompt = `Generate a concise comment explaining the changes introduced by the following git commit diff. Format it nicely using Markdown.\n\nGit diff:\n\`\`\`diff\n${diff}\n\`\`\``;
285+
let generatedDescription = 'Applied automated code changes.';
286+
try {
287+
const completion = await client.chat.completions.create({
288+
model: modelName,
289+
messages: [{ role: 'user', content: prompt }],
290+
});
291+
generatedDescription = completion.choices[0].message.content;
292+
} catch (error) {
293+
console.error("Error generating comment description:", error);
294+
}
295+
296+
let commentBody = `🤖 LLM Coder applied the following changes based on your request:\n\n${generatedDescription}\n\n---\n*Changes pushed to branch \`${branchName}\`.*`;
297+
298+
// PRのdiffコメントの場合は、そのスレッドに返信
299+
if (context.eventName === 'pull_request_review_comment') {
300+
const comment = await github.rest.pulls.createReplyForReviewComment({
301+
owner,
302+
repo,
303+
pull_number: prNumber,
304+
comment_id: context.payload.comment.id,
305+
body: commentBody
306+
});
307+
console.log(`Reply added to review comment: ${comment.data.html_url}`);
308+
} else {
309+
// それ以外の場合は PR 全体にコメント
310+
const comment = await github.rest.issues.createComment({
311+
owner,
312+
repo,
313+
issue_number: prNumber,
314+
body: commentBody
315+
});
316+
console.log(`Comment added: ${comment.data.html_url}`);
317+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ wheels/
1212
.mypy_cache/
1313
.ruff_cache/
1414
.pytest_cache/
15+
llm_coder_config.toml

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.11

0 commit comments

Comments
 (0)