Skip to content

Commit 9046fe2

Browse files
kgpaimeta-codesync[bot]
authored andcommitted
fix: Update review bot to use results response (#16536)
Summary: Update the claude yml job to use the `results` response and not the `assistants` response. Also save the claude action response as an artifact. Pull Request resolved: #16536 Reviewed By: kevinwilfong Differential Revision: D94435547 Pulled By: kgpai fbshipit-source-id: 1b23386179150126ff528add44f90eab05a1023f
1 parent 53dcda0 commit 9046fe2

File tree

1 file changed

+46
-74
lines changed

1 file changed

+46
-74
lines changed

.github/workflows/claude-review.yml

Lines changed: 46 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,17 @@ jobs:
269269
--allowedTools View,GlobTool,GrepTool
270270
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
271271

272-
# Step 7: Post review as PR comment (skip if dry_run)
272+
# Step 7: Save execution log as artifact for debugging
273+
- name: Upload execution log
274+
if: always()
275+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
276+
with:
277+
name: claude-execution-log-${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.issue.number }}
278+
path: ${{ steps.claude_review.outputs.execution_file }}
279+
retention-days: 7
280+
if-no-files-found: warn
281+
282+
# Step 8: Post review as PR comment (skip if dry_run)
273283
- name: Post review comment
274284
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.dry_run) }}
275285
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
@@ -285,67 +295,27 @@ jobs:
285295
let reviewBody = '';
286296
287297
try {
288-
// Read the execution log
289-
const fileContent = fs.readFileSync(process.env.EXECUTION_FILE, 'utf8');
290-
const executionLog = JSON.parse(fileContent);
298+
// Read the execution log (array of messages from claude-code-base-action)
299+
const executionLog = JSON.parse(fs.readFileSync(process.env.EXECUTION_FILE, 'utf8'));
291300
292-
// Log structure for debugging
293-
console.log('Execution log type:', Array.isArray(executionLog) ? 'array' : typeof executionLog);
294301
if (!Array.isArray(executionLog)) {
295-
console.log('Execution log keys:', Object.keys(executionLog));
302+
throw new Error('Expected array format from claude-code-base-action');
296303
}
297304
298-
// Helper function to extract text from assistant messages
299-
const extractFromMessages = (messages) => {
300-
const assistantMessages = messages.filter(m => m.role === 'assistant');
301-
if (assistantMessages.length > 0) {
302-
const lastMessage = assistantMessages[assistantMessages.length - 1];
303-
if (typeof lastMessage.content === 'string') {
304-
return lastMessage.content;
305-
} else if (Array.isArray(lastMessage.content)) {
306-
return lastMessage.content
307-
.filter(block => block.type === 'text')
308-
.map(block => block.text)
309-
.join('\n\n');
310-
}
311-
}
312-
return null;
313-
};
314-
315-
// Try different possible structures from claude-code-base-action
316-
if (Array.isArray(executionLog)) {
317-
// claude-code-base-action writes messages array directly to file
318-
const extracted = extractFromMessages(executionLog);
319-
if (extracted) {
320-
reviewBody = extracted;
321-
} else {
322-
console.log('No assistant messages found in array');
323-
reviewBody = '⚠️ No assistant response found in execution log.';
324-
}
325-
} else if (executionLog.result) {
326-
// Direct result field
327-
reviewBody = executionLog.result;
328-
} else if (executionLog.output) {
329-
// Output field
330-
reviewBody = executionLog.output;
331-
} else if (executionLog.response) {
332-
// Response field
333-
reviewBody = executionLog.response;
334-
} else if (executionLog.messages && Array.isArray(executionLog.messages)) {
335-
// Messages array inside object
336-
const extracted = extractFromMessages(executionLog.messages);
337-
if (extracted) {
338-
reviewBody = extracted;
339-
} else {
340-
reviewBody = '⚠️ No assistant response found in messages.';
341-
}
342-
} else if (typeof executionLog === 'string') {
343-
// Plain string
344-
reviewBody = executionLog;
305+
// Find the "result" message which contains the final review
306+
const resultMessage = executionLog.find(m => m.type === 'result');
307+
308+
if (!resultMessage) {
309+
reviewBody = '⚠️ No result message found in execution log.';
310+
} else if (resultMessage.subtype === 'success' && resultMessage.result) {
311+
reviewBody = resultMessage.result;
312+
} else if (resultMessage.is_error || resultMessage.subtype === 'error') {
313+
const errorInfo = resultMessage.result || resultMessage.error || 'Unknown error';
314+
reviewBody = `❌ **Claude Code encountered an error:**\n\n${errorInfo}`;
315+
} else if (resultMessage.result) {
316+
reviewBody = `⚠️ **Review completed with status: ${resultMessage.subtype}**\n\n${resultMessage.result}`;
345317
} else {
346-
// Fallback: stringify the whole thing
347-
console.log('Unknown format, raw content:', JSON.stringify(executionLog).substring(0, 500));
348-
reviewBody = '⚠️ Could not parse Claude response format. Check workflow logs for details.';
318+
reviewBody = '⚠️ Claude completed but produced no review output.';
349319
}
350320
} catch (error) {
351321
console.error('Error parsing execution log:', error);
@@ -385,35 +355,37 @@ jobs:
385355
body: fullComment
386356
});
387357
388-
# Step 7b: Print review to logs if dry_run
358+
# Step 8b: Print review to logs if dry_run
389359
- name: Print review to logs (dry run)
390360
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
391361
env:
392362
EXECUTION_FILE: ${{ steps.claude_review.outputs.execution_file }}
393363
run: |
394364
echo "=== DRY RUN - Review would be posted as comment ==="
395365
echo ""
396-
echo "=== Execution file structure ==="
397-
# Check if it's an array (claude-code-base-action format) or object
398-
if jq -e 'type == "array"' "$EXECUTION_FILE" >/dev/null 2>&1; then
399-
echo "Format: array of messages (length: $(jq 'length' "$EXECUTION_FILE"))"
400-
else
401-
jq 'keys' "$EXECUTION_FILE" 2>/dev/null || echo "Not valid JSON or file not found"
402-
fi
403-
echo ""
404-
echo "=== Attempting to extract review ==="
405-
# Try array format first (claude-code-base-action), then object formats
406-
if jq -e 'type == "array"' "$EXECUTION_FILE" >/dev/null 2>&1; then
407-
# Array format: extract last assistant message content
408-
jq -r '[.[] | select(.role == "assistant")] | last | if .content | type == "string" then .content elif .content | type == "array" then [.content[] | select(.type == "text") | .text] | join("\n\n") else "Could not extract" end' "$EXECUTION_FILE" 2>/dev/null || cat "$EXECUTION_FILE"
366+
echo "=== Extracting review from result message ==="
367+
# Find the "result" message and extract based on subtype
368+
RESULT_MSG=$(jq '[.[] | select(.type == "result")] | .[0]' "$EXECUTION_FILE" 2>/dev/null)
369+
if [ "$RESULT_MSG" = "null" ] || [ -z "$RESULT_MSG" ]; then
370+
echo "⚠️ No result message found"
409371
else
410-
# Object format: try different possible paths
411-
jq -r '.result // .output // .response // .messages[-1].content // "Could not extract"' "$EXECUTION_FILE" 2>/dev/null || cat "$EXECUTION_FILE"
372+
SUBTYPE=$(echo "$RESULT_MSG" | jq -r '.subtype // "unknown"')
373+
echo "Status: $SUBTYPE"
374+
echo ""
375+
if [ "$SUBTYPE" = "success" ]; then
376+
echo "$RESULT_MSG" | jq -r '.result // "No result field"'
377+
elif [ "$SUBTYPE" = "error" ]; then
378+
echo "❌ Error:"
379+
echo "$RESULT_MSG" | jq -r '.result // .error // "Unknown error"'
380+
else
381+
echo "⚠️ Status: $SUBTYPE"
382+
echo "$RESULT_MSG" | jq -r '.result // "No result"'
383+
fi
412384
fi
413385
echo ""
414386
echo "=== End of review ==="
415387
416-
# Step 8: Update reaction on completion (only for issue_comment trigger)
388+
# Step 9: Update reaction on completion (only for issue_comment trigger)
417389
- name: Update reaction on success
418390
if: success() && github.event_name == 'issue_comment'
419391
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1

0 commit comments

Comments
 (0)