feat: add context budget system for LLM overflow (#19)
Adds a budget package that estimates token usage and progressively trims context to fit within model-specific limits. Trim order (least important first): 1. Language patterns 2. Repository conventions 3. Full file context 4. Diff (truncated as last resort) When content is trimmed, a note is appended to the user prompt so the LLM knows context was reduced. - New budget package with Fit(), EstimateTokens(), LimitForModel() - Model limit table (GPT-4.1: 128K, GPT-5: 200K, Claude: 200K) - Refactored review/prompt.go: BuildSystemBase() and BuildUserMeta() extract non-trimmable content; old functions delegate to new ones - main.go uses budget.Fit() instead of direct prompt assembly - 7 unit tests covering all trim paths Closes #19
This commit is contained in:
+26
-4
@@ -7,8 +7,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BuildSystemPrompt constructs the system prompt for the LLM reviewer.
|
||||
func BuildSystemPrompt(conventions, patterns string) string {
|
||||
// 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")
|
||||
@@ -42,6 +44,15 @@ func BuildSystemPrompt(conventions, patterns string) string {
|
||||
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))
|
||||
}
|
||||
@@ -53,8 +64,9 @@ func BuildSystemPrompt(conventions, patterns string) string {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// BuildUserPrompt constructs the user message with PR context.
|
||||
func BuildUserPrompt(title, description, diff, fileContext string, ciPassed bool, ciDetails string) 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))
|
||||
@@ -73,6 +85,16 @@ func BuildUserPrompt(title, description, diff, fileContext string, ciPassed bool
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user