// Package review builds prompts for AI code review and parses LLM responses // into structured review results. package review import ( "fmt" "strings" ) // outputSchemaJSON is the shared JSON output format specification used by both // the generic reviewer and persona-based reviewers. const outputSchemaJSON = `{ "verdict": "APPROVE" or "REQUEST_CHANGES", "summary": "Brief overall assessment (1-3 sentences)", "findings": [ { "severity": "MAJOR" or "MINOR" or "NIT", "file": "path/to/file", "line": , "finding": "Description of the issue" } ], "recommendation": "Full recommendation text explaining your verdict" }` // verdictRules is the shared verdict determination rules. const verdictRules = `Rules: - If there are any MAJOR findings → verdict must be REQUEST_CHANGES - If there are no MAJOR findings → verdict should be APPROVE - If CI has failed → verdict must be REQUEST_CHANGES with a finding noting the CI failure` // BuildSystemBase returns the core system prompt instructions without // patterns or conventions. Used by the budget package to separate // trimmable from non-trimmable content. func BuildSystemBase() string { var sb strings.Builder sb.WriteString("You are an expert code reviewer. Review the provided pull request diff carefully.\n\n") sb.WriteString("CONTEXT:\n") sb.WriteString("- You will receive the full content of modified files for reference, followed by the diff showing what changed.\n") sb.WriteString("- The diff shows ONLY what was added/removed. The full file content provides complete context.\n") sb.WriteString("- Focus your review on the CHANGES (the diff), using the full files for context.\n\n") sb.WriteString("Your task:\n") sb.WriteString("1. Review the diff for correctness, idiomatic code, potential bugs, and design issues.\n") sb.WriteString("2. Consider the CI status — if CI has failed, that is an automatic REQUEST_CHANGES regardless of code quality.\n") sb.WriteString("3. Output your review as structured JSON (and ONLY JSON, no markdown fences or other text).\n\n") sb.WriteString("Output format:\n") sb.WriteString(outputSchemaJSON) sb.WriteString("\n\n") sb.WriteString(verdictRules) sb.WriteString("\n- Be thorough but fair. Don't nitpick style unless it impacts readability significantly.\n") sb.WriteString("- Line numbers should reference the new file line numbers from the diff headers.\n") sb.WriteString("- If the diff is empty or trivial (only formatting/whitespace), APPROVE with no findings.\n") return sb.String() } // BuildSystemPrompt constructs the full system prompt with patterns and conventions. // Deprecated: Use BuildSystemBase with budget.Fit for context-aware assembly. func BuildSystemPrompt(conventions, patterns string) string { var sb strings.Builder sb.WriteString(BuildSystemBase()) if patterns != "" { sb.WriteString(fmt.Sprintf("\n\n## Language Patterns & Idioms\n\nUse the following patterns as review criteria. Code that violates these established patterns is a finding:\n\n%s\n", patterns)) } if conventions != "" { sb.WriteString(fmt.Sprintf("\n\n## Repository Conventions\n\nThe repository has the following coding conventions that must be respected:\n\n%s\n", conventions)) } return sb.String() } // BuildUserMeta returns the PR metadata header (title, description, CI status) // without the diff or file context. Used by the budget package. func BuildUserMeta(title, description string, ciPassed bool, ciDetails string) string { var sb strings.Builder sb.WriteString(fmt.Sprintf("## Pull Request: %s\n\n", title)) if description != "" { sb.WriteString(fmt.Sprintf("### Description\n%s\n\n", description)) } ciStatus := "PASSED" if !ciPassed { ciStatus = "FAILED" } sb.WriteString(fmt.Sprintf("### CI Status: %s\n", ciStatus)) if ciDetails != "" { sb.WriteString(fmt.Sprintf("CI Details: %s\n", ciDetails)) } return sb.String() } // BuildUserPrompt constructs the user message with PR context. // Deprecated: Use BuildUserMeta with budget.Fit for context-aware assembly. func BuildUserPrompt(title, description, diff, fileContext string, ciPassed bool, ciDetails string) string { var sb strings.Builder sb.WriteString(BuildUserMeta(title, description, ciPassed, ciDetails)) if fileContext != "" { sb.WriteString("\n### Full File Context (modified files)\n\n") sb.WriteString(fileContext) sb.WriteString("\n") } sb.WriteString("\n### Diff (changes to review)\n\n") sb.WriteString("```diff\n") sb.WriteString(diff) sb.WriteString("\n```\n") return sb.String() }