@@ -59,175 +59,3 @@ jobs:
5959 EDGE-CASE-TESTS_RESULTS : " ${{steps.edge-case-tests.outputs.result}}"
6060 with :
6161 runners : compilation-check,basic-tests,edge-case-tests
62- ai_feedback :
63- name : AI-Powered Feedback
64- needs : run-autograding-tests
65- if : ${{ needs.run-autograding-tests.result == 'success' }}
66- runs-on : ubuntu-latest
67- permissions :
68- pull-requests : write
69- env :
70- OPENROUTER_MODEL : ${{ vars.OPENROUTER_MODEL }}
71- SYSTEM_PROMPT : ${{ vars.SYSTEM_PROMPT }}
72- steps :
73- - name : Checkout repository
74- uses : actions/checkout@v5
75-
76- - name : Read assignment instructions
77- id : instructions
78- run : |
79- # Reads the content of the README.md file into an output variable.
80- # The `EOF` marker is used to handle multi-line file content.
81- echo "instructions=$(cat README.md | sed 's/\"/\\\"/g' | sed 's/$/\\n/' | tr -d '\n' | sed 's/\\n/\\\\n/g')" >> $GITHUB_OUTPUT
82-
83- - name : Read source code
84- id : source_code
85- run : |
86- {
87- echo 'source_code<<EOF'
88- find src/main/java -type f -name "*.java" | while read -r file; do
89- echo "=== File: $file ==="
90- cat "$file"
91- echo
92- done
93- echo 'EOF'
94- } >> "$GITHUB_OUTPUT"
95-
96- - name : Read test code
97- id : test_code
98- run : |
99- {
100- echo 'test_code<<EOF'
101- if [ -d "src/test/java" ]; then
102- find src/test/java -type f -name "*.java" | while read -r file; do
103- echo "=== File: $file ==="
104- cat "$file"
105- echo
106- done
107- else
108- echo "No test code found."
109- fi
110- echo 'EOF'
111- } >> "$GITHUB_OUTPUT"
112- - name : Generate AI Feedback
113- id : ai_feedback
114- run : |
115- # This step sends the collected data to the OpenRouter API.
116- INSTRUCTIONS=$(jq -Rs . <<'EOF'
117- ${{ steps.instructions.outputs.instructions }}
118- EOF
119- )
120- SOURCE_CODE=$(jq -Rs . <<'EOF'
121- ${{ steps.source_code.outputs.source_code }}
122- EOF
123- )
124- TEST_CODE=$(jq -Rs . <<'EOF'
125- ${{ steps.test_code.outputs.test_code }}
126- EOF
127- )
128-
129- if [ -z "$INSTRUCTIONS" ] || [ -z "$SOURCE_CODE" ] || [ -z "$TEST_CODE" ]; then
130- echo "Error: One or more required variables are not set."
131- exit 1
132- fi
133-
134- # Assigning to USER_CONTENT with variable expansion
135- PAYLOAD="Please provide feedback on the following Java assignment.
136-
137- --- Assignment Instructions ---
138- ${INSTRUCTIONS}
139-
140- --- Source files ---
141- ${SOURCE_CODE}
142-
143- --- Test files ---
144- ${TEST_CODE}"
145-
146- JSON_CONTENT=$(jq -n \
147- --argjson model "$OPENROUTER_MODEL" \
148- --arg system_prompt "$SYSTEM_PROMPT" \
149- --arg payload "$PAYLOAD" \
150- '{
151- models: $model,
152- messages: [
153- {role: "system", content: $system_prompt},
154- {role: "user", content: $payload}
155- ]
156- }')
157-
158- echo "$JSON_CONTENT"
159-
160- API_RESPONSE=$(echo "$JSON_CONTENT" | curl https://openrouter.ai/api/v1/chat/completions \
161- -H "Authorization: Bearer ${{ secrets.OPENROUTER_API_KEY }}" \
162- -H "Content-Type: application/json" \
163- -d @-)
164-
165- echo "$API_RESPONSE"
166-
167- FEEDBACK_CONTENT=$(echo "$API_RESPONSE" | jq -r '.choices[0].message.content')
168- echo "feedback<<EOF" >> $GITHUB_OUTPUT
169- echo "$FEEDBACK_CONTENT" >> $GITHUB_OUTPUT
170- echo "EOF" >> $GITHUB_OUTPUT
171- - name : Post Feedback as PR Comment ✍️
172- uses : actions/github-script@v7
173- env :
174- FEEDBACK_BODY : ${{ steps.ai_feedback.outputs.feedback }}
175- with :
176- github-token : ${{ secrets.GITHUB_TOKEN }}
177- script : |
178- const { owner, repo } = context.repo;
179- const targetTitle = "Feedback";
180- const signature = "🤖 AI Feedback";
181-
182- const { data: pullRequests } = await github.rest.pulls.list({
183- owner,
184- repo,
185- state: "open",
186- per_page: 100
187- });
188-
189- const matchingPR = pullRequests.find(pr => pr.title.trim().toLowerCase() === targetTitle.toLowerCase());
190- if (!matchingPR) {
191- throw new Error(`No open pull request found with title '${targetTitle}'`);
192- }
193-
194- const prNumber = matchingPR.number;
195-
196- const { data: comments } = await github.rest.issues.listComments({
197- owner,
198- repo,
199- issue_number: prNumber,
200- per_page: 100
201- });
202-
203- const existing = comments.find(c =>
204- c.user?.login === "github-actions[bot]" &&
205- c.body?.includes(signature)
206- );
207-
208- const timestamp = new Date().toISOString();
209- const newEntry = `🕒 _Posted on ${timestamp}_\n\n${process.env.FEEDBACK_BODY}\n\n---\n`;
210-
211- if (existing) {
212- // Extract previous entries and wrap them in a collapsible block
213- const previousContent = existing.body.replace(/^### 🤖 AI Feedback\s*/, '').trim();
214- const collapsed = `<details><summary>Previous Feedback</summary>\n\n${previousContent}\n</details>`;
215-
216- const updatedBody = `### ${signature}\n\n${newEntry}${collapsed}`;
217- await github.rest.issues.updateComment({
218- owner,
219- repo,
220- comment_id: existing.id,
221- body: updatedBody
222- });
223- console.log(`🔄 Updated existing comment on PR #${prNumber}`);
224- } else {
225- const body = `### ${signature}\n\n${newEntry}`;
226- await github.rest.issues.createComment({
227- owner,
228- repo,
229- issue_number: prNumber,
230- body
231- });
232- console.log(`🆕 Posted new comment on PR #${prNumber}`);
233- }
0 commit comments