feat(pierre): sanity check
This commit is contained in:
@@ -37,6 +37,15 @@ func (g *mockGit) AddComment(ctx context.Context, owner, repo string, prID int,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *mockGit) GetFileContent(ctx context.Context, owner, repo, path, ref string) (string, error) {
|
||||
// For tests, return a simple placeholder content.
|
||||
return "package main\n\nfunc placeholder() {}", nil
|
||||
}
|
||||
|
||||
func (g *mockGit) GetPRHeadSHA(ctx context.Context, owner, repo string, prID int) (string, error) {
|
||||
return "dummysha", nil
|
||||
}
|
||||
|
||||
func TestSplitDiffIntoChunks(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
|
||||
@@ -33,6 +33,8 @@ func New(chat ChatAdapter, git GitAdapter, maxChunkSize int, guidelines []string
|
||||
type GitAdapter interface {
|
||||
GetDiff(ctx context.Context, owner, repo string, prID int) (io.ReadCloser, error)
|
||||
AddComment(ctx context.Context, owner, repo string, prID int, comment Comment) error
|
||||
GetFileContent(ctx context.Context, owner, repo, path, ref string) (string, error)
|
||||
GetPRHeadSHA(ctx context.Context, owner, repo string, prID int) (string, error)
|
||||
}
|
||||
|
||||
type ChatAdapter interface {
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/chatter"
|
||||
)
|
||||
|
||||
func (s *Service) MakeReview(ctx context.Context, organisation string, repo string, prID int) error {
|
||||
@@ -20,6 +22,46 @@ func (s *Service) MakeReview(ctx context.Context, organisation string, repo stri
|
||||
return fmt.Errorf("error judging PR: %w", err)
|
||||
}
|
||||
|
||||
// ---------- Sanity‑check step (always enabled) ----------
|
||||
headSHA, err := s.git.GetPRHeadSHA(ctx, organisation, repo, prID)
|
||||
if err != nil {
|
||||
log.Printf("warning: could not fetch PR head SHA (%v); skipping sanity check", err)
|
||||
} else {
|
||||
filtered := []Comment{}
|
||||
for _, c := range comments {
|
||||
// Retrieve full file content at the PR head
|
||||
fileContent, fErr := s.git.GetFileContent(ctx, organisation, repo, c.File, headSHA)
|
||||
if fErr != nil {
|
||||
log.Printf("failed to fetch file %s: %v – keeping original comment", c.File, fErr)
|
||||
filtered = append(filtered, c)
|
||||
continue
|
||||
}
|
||||
|
||||
// Build a simple sanity‑check prompt
|
||||
systemPrompt := `You are a senior software architect. Given the full source code of a file and a review comment that refers to it, decide whether the comment is useful. Return JSON with fields "useful" (bool) and "reason" (short explanation, ≤2 sentences).`
|
||||
userPrompt := fmt.Sprintf("File content:\n%s\n\nComment:\n%s", fileContent, c.Message)
|
||||
|
||||
type sanityResult struct {
|
||||
Useful bool `json:"useful"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
var res sanityResult
|
||||
if err := s.chat.GenerateStructured(ctx, []chatter.Message{{Role: chatter.RoleSystem, Content: systemPrompt}, {Role: chatter.RoleUser, Content: userPrompt}}, &res); err != nil {
|
||||
log.Printf("sanity check error for %s:%d: %v – keeping comment", c.File, c.Line, err)
|
||||
filtered = append(filtered, c)
|
||||
continue
|
||||
}
|
||||
if res.Useful {
|
||||
// Optionally annotate the comment with the reason for debugging
|
||||
c.Message = fmt.Sprintf("%s (Reason: %s)", c.Message, res.Reason)
|
||||
filtered = append(filtered, c)
|
||||
} else {
|
||||
log.Printf("comment on %s:%d discarded: %s", c.File, c.Line, res.Reason)
|
||||
}
|
||||
}
|
||||
comments = filtered
|
||||
}
|
||||
|
||||
fmt.Printf("Analysis complete. Found %d issues.\n---\n", len(comments))
|
||||
|
||||
model := s.chat.GetProviderName()
|
||||
|
||||
Reference in New Issue
Block a user