#!/usr/bin/env bash # Required env vars: AI_API_URL, AI_API_KEY, AI_MODEL, PR_TITLE, PR_BODY # Optional env vars: PREV_REVIEW, INCREMENTAL # Reads: pr.diff, prompts/review.md (or prompts/review-update.md for incremental) # Writes: $GITHUB_OUTPUT (review) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROMPTS_DIR="${SCRIPT_DIR}/../prompts" DIFF=$(cat pr.diff) echo "Diff size: $(wc -c < pr.diff) bytes" if [ "${INCREMENTAL:-false}" = "true" ] && [ -n "${PREV_REVIEW:-}" ]; then echo "Building incremental review with conversation history" SYSTEM_PROMPT=$(cat "${PROMPTS_DIR}/review-update.md") # Reconstruct conversation: the model previously reviewed an earlier state, # now we show it only what changed since then. MESSAGES=$(jq -n \ --arg system "$SYSTEM_PROMPT" \ --arg prev "$PREV_REVIEW" \ --arg title "$PR_TITLE" \ --arg body "$PR_BODY" \ --arg diff "$DIFF" \ '[ { role: "system", content: $system }, { role: "assistant", content: $prev }, { role: "user", content: ("The PR has been updated. Here are the new changes since your last review.\n\nPR Title: " + $title + "\nPR Description: " + $body + "\n\nIncremental diff:\n```diff\n" + $diff + "\n```\n\nUpdate your review, keeping previous feedback relevant to unchanged code and focusing new commentary on what has changed.") } ]') else echo "Building full review" SYSTEM_PROMPT=$(cat "${PROMPTS_DIR}/review.md") MESSAGES=$(jq -n \ --arg system "$SYSTEM_PROMPT" \ --arg title "$PR_TITLE" \ --arg body "$PR_BODY" \ --arg diff "$DIFF" \ '[ { role: "system", content: $system }, { role: "user", content: ("PR Title: " + $title + "\nPR Description: " + $body + "\n\nDiff:\n```diff\n" + $diff + "\n```") } ]') fi PAYLOAD=$(jq -n \ --arg model "$AI_MODEL" \ --argjson messages "$MESSAGES" \ '{ model: $model, messages: $messages, max_tokens: 1024, temperature: 0.2 }') echo "Payload size: $(echo "$PAYLOAD" | wc -c) bytes" echo "Calling endpoint: ${AI_API_URL%/}/chat/completions" echo "Model: ${AI_MODEL}" HTTP_RESPONSE=$(curl -s \ --max-time 120 \ -w "\n__HTTP_STATUS__:%{http_code}" \ -H "Authorization: Bearer ${AI_API_KEY}" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "${AI_API_URL%/}/chat/completions") CURL_EXIT=$? HTTP_STATUS=$(echo "$HTTP_RESPONSE" | grep '__HTTP_STATUS__:' | cut -d: -f2) RESPONSE_BODY=$(echo "$HTTP_RESPONSE" | sed '/__HTTP_STATUS__:/d') echo "curl exit code: ${CURL_EXIT}" echo "HTTP status: ${HTTP_STATUS}" echo "Response body: ${RESPONSE_BODY}" if [ "$CURL_EXIT" -ne 0 ]; then echo "::error::curl failed with exit code ${CURL_EXIT}" exit 1 fi if [ "$HTTP_STATUS" -lt 200 ] || [ "$HTTP_STATUS" -ge 300 ]; then echo "::error::API returned HTTP ${HTTP_STATUS}: ${RESPONSE_BODY}" exit 1 fi REVIEW=$(echo "$RESPONSE_BODY" | jq -r '.choices[0].message.content') if [ -z "$REVIEW" ] || [ "$REVIEW" = "null" ]; then echo "::error::Failed to extract review from response. Full body: ${RESPONSE_BODY}" exit 1 fi echo "Review length: $(echo "$REVIEW" | wc -c) chars" echo "review<> "$GITHUB_OUTPUT" echo "$REVIEW" >> "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT"