mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(tools) limit edit diff preview size for user and model
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
)
|
||||
@@ -12,6 +13,11 @@ import (
|
||||
const (
|
||||
noContentChangeDiffMessage = "(no content change)"
|
||||
noNewlineAtEOFMarker = `\ No newline at end of file`
|
||||
diffPreviewSkippedMessage = "[diff preview skipped: file too large for inline preview]"
|
||||
diffPreviewTruncatedNote = "[diff preview truncated; call read_file for the full edited contents]"
|
||||
maxDiffInputBytes = 64 * 1024
|
||||
maxDiffInputLines = 2000
|
||||
maxUserDiffPreviewBytes = 16 * 1024
|
||||
)
|
||||
|
||||
// DiffResult creates a user-visible tool result containing a unified diff for
|
||||
@@ -19,13 +25,36 @@ const (
|
||||
// the follow-up assistant response can reason about the resulting change set,
|
||||
// including EOF newline transitions.
|
||||
func DiffResult(path string, before, after []byte) *ToolResult {
|
||||
diff, err := buildUnifiedDiff(path, before, after)
|
||||
if err != nil {
|
||||
return UserResult(fmt.Sprintf("File edited: %s\n[diff unavailable: %v]", path, err))
|
||||
summary := fmt.Sprintf("File edited: %s", path)
|
||||
if exceedsDiffPreviewLimits(before, after) {
|
||||
return SilentResult(summary + "\n" + diffPreviewSkippedMessage)
|
||||
}
|
||||
|
||||
content := fmt.Sprintf("File edited: %s\n```diff\n%s\n```", path, diff)
|
||||
return UserResult(content)
|
||||
diff, err := buildUnifiedDiff(path, before, after)
|
||||
if err != nil {
|
||||
return UserResult(fmt.Sprintf("%s\n[diff unavailable: %v]", summary, err))
|
||||
}
|
||||
|
||||
userDiff, truncated := truncateDiffPreview(diff, maxUserDiffPreviewBytes)
|
||||
userContent := fmt.Sprintf("%s\n```diff\n%s\n```", summary, userDiff)
|
||||
if truncated {
|
||||
userContent += "\n" + diffPreviewTruncatedNote
|
||||
}
|
||||
|
||||
llmContent := summary
|
||||
if diff == noContentChangeDiffMessage {
|
||||
llmContent = summary + "\n" + noContentChangeDiffMessage
|
||||
} else if truncated {
|
||||
llmContent = summary + "\n" + diffPreviewTruncatedNote
|
||||
}
|
||||
|
||||
return &ToolResult{
|
||||
ForLLM: llmContent,
|
||||
ForUser: userContent,
|
||||
Silent: false,
|
||||
IsError: false,
|
||||
Async: false,
|
||||
}
|
||||
}
|
||||
|
||||
func buildUnifiedDiff(path string, before, after []byte) (string, error) {
|
||||
@@ -78,6 +107,52 @@ func lacksTrailingNewline(content []byte) bool {
|
||||
return len(content) > 0 && !bytes.HasSuffix(content, []byte("\n"))
|
||||
}
|
||||
|
||||
func exceedsDiffPreviewLimits(before, after []byte) bool {
|
||||
return len(before) > maxDiffInputBytes ||
|
||||
len(after) > maxDiffInputBytes ||
|
||||
countDiffLines(before) > maxDiffInputLines ||
|
||||
countDiffLines(after) > maxDiffInputLines
|
||||
}
|
||||
|
||||
func countDiffLines(content []byte) int {
|
||||
if len(content) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
lines := bytes.Count(content, []byte{'\n'})
|
||||
if !bytes.HasSuffix(content, []byte("\n")) {
|
||||
lines++
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func truncateDiffPreview(diff string, maxBytes int) (string, bool) {
|
||||
if maxBytes <= 0 || len(diff) <= maxBytes {
|
||||
return diff, false
|
||||
}
|
||||
|
||||
truncated := diff[:maxBytes]
|
||||
for len(truncated) > 0 && !utf8.ValidString(truncated) {
|
||||
truncated = truncated[:len(truncated)-1]
|
||||
}
|
||||
|
||||
lastNewline := strings.LastIndexByte(truncated, '\n')
|
||||
if lastNewline > 0 {
|
||||
truncated = truncated[:lastNewline]
|
||||
}
|
||||
|
||||
truncated = strings.TrimRight(truncated, "\n")
|
||||
if truncated == "" {
|
||||
truncated = diff[:maxBytes]
|
||||
for len(truncated) > 0 && !utf8.ValidString(truncated) {
|
||||
truncated = truncated[:len(truncated)-1]
|
||||
}
|
||||
truncated = strings.TrimRight(truncated, "\n")
|
||||
}
|
||||
|
||||
return truncated, true
|
||||
}
|
||||
|
||||
func diffDisplayPath(path string) string {
|
||||
displayPath := strings.TrimLeft(filepath.ToSlash(path), "/")
|
||||
if displayPath == "" {
|
||||
|
||||
Reference in New Issue
Block a user