blob: 541ee5298778f955e54c89a108bda0002147e62c [file] [log] [blame]
Josh Bleecher Snyderf4047bb2025-05-05 23:02:56 +00001package codereview
Josh Bleecher Snydere2518e52025-04-29 11:13:40 -07002
3import (
4 "context"
5 _ "embed"
6 "fmt"
7 "os/exec"
8 "strings"
9
10 "sketch.dev/llm"
11 "sketch.dev/llm/conversation"
12)
13
14//go:embed llm_codereview_prompt.txt
15var llmCodereviewPrompt string
16
17// doLLMReview analyzes the diff using an LLM subagent.
18func (r *CodeReviewer) doLLMReview(ctx context.Context) (string, error) {
19 // Get the full diff between initial commit and HEAD
20 cmd := exec.CommandContext(ctx, "git", "diff", r.initialCommit, "HEAD")
21 cmd.Dir = r.repoRoot
22 out, err := cmd.CombinedOutput()
23 if err != nil {
24 return "", fmt.Errorf("failed to get diff: %w\n%s", err, out)
25 }
26
27 // If no diff, nothing to check
28 if len(out) == 0 {
29 return "", nil
30 }
31
32 info := conversation.ToolCallInfoFromContext(ctx)
33 convo := info.Convo.SubConvo()
34 convo.SystemPrompt = strings.TrimSpace(llmCodereviewPrompt)
35 initialMessage := llm.UserStringMessage("<diff>\n" + string(out) + "\n</diff>")
36
37 resp, err := convo.SendMessage(initialMessage)
38 if err != nil {
39 return "", fmt.Errorf("failed to send LLM codereview message: %w", err)
40 }
41 if len(resp.Content) != 1 {
42 return "", fmt.Errorf("unexpected number of content blocks in LLM codereview response: %d", len(resp.Content))
43 }
44
45 response := resp.Content[0].Text
46 if strings.TrimSpace(response) == "No comments." {
47 return "", nil
48 }
49 return response, nil
50}